LaravelでYamlファイルを簡単に扱う方法


はじめに

何かといろいろな活用法があるYamlファイル。この記事では、Laravelで指定ディレクトリ以下のYamlファイルを読み取り、配列に変換したうえで取得する方法について解説します。

使用ライブラリ

  • symfony/yaml

動作確認環境

  • PHP-8.0
  • Laravel-8.0

インストール

以下は開発環境でのみYamlファイルを使用する場合のインストール方法です。
本番環境でも使用する想定がある場合は--devを外して下さい。

composer require --dev symfony/yaml

サンプルコード

下記クラスをコンストラクトインジェクションする。またはクラスをmakeして下さい。
なお、ネームスペースは適時変更下さい。

Reader.php
<?php

namespace Hogehoge;

use File;
use Illuminate\Filesystem\Filesystem;
use LogicException;
use Symfony\Component\Yaml\Yaml;

/**
 * Class Reader
 */
class Reader
{
    /**
     * @var \Symfony\Component\Yaml\Yaml
     */
    protected $yaml;

    /**
     * @var \Illuminate\Filesystem\Filesystem
     */
    protected $file;

    /**
     * YamlFileOperation constructor.
     */
    public function __construct(
        Filesystem $file,
        Yaml $yaml
    ) {
        $this->yaml = $yaml;
        $this->file = $file;
    }

    /**
     * Read yaml files.
     *
     * @param  string  $directoryPath
     * @param  array  $exceptFileNames
     * @return array
     */
    public function readFileByDirectoryPath(string $directoryPath, array $exceptFileNames = []): array
    {
        $yamlFiles = $this->readByDirectoryPath($directoryPath);

        // Exclude from creation
        if (! empty($exceptFileNames) && ! empty($yamlFiles)) {
            $yamlFiles = collect($yamlFiles)->filter(function ($value, $key) use ($exceptFileNames) {
                return ! in_array(basename($key, '.yml'), $exceptFileNames, false);
            })->all();
        }

        return $yamlFiles;
    }

    /**
     * Read yaml files.
     *
     * @param  string  $directoryPath
     * @param  string  $findFileName
     * @return array
     */
    public function readFileByFileName(string $directoryPath, string $findFileName): array
    {
        $yamlFiles = $this->readFileByDirectoryPath($directoryPath);

        foreach ($yamlFiles as $fileName => $yamlFile) {
            if (basename($fileName, '.yml') === $findFileName) {
                return $yamlFile;
            }
        }

        return [];
    }

    /**
     * Reading definition data.
     *
     * @param  string  $targetDirectoryPath
     * @return array
     */
    protected function readByDirectoryPath(string $targetDirectoryPath): array
    {
        if (! $this->file->isDirectory($targetDirectoryPath)) {
            throw new LogicException($targetDirectoryPath.': read path must be a directory');
        }

        $filePaths = $this->getAllFilePath($targetDirectoryPath);

        return $this->parseAllYaml($filePaths);
    }

    /**
     * Recursively get a list of file paths from a directory.
     *
     * @param  string  $directoryPath
     * @return array
     */
    protected function getAllFilePath(string $directoryPath): array
    {
        $filePaths = [];

        if (! $this->file->isDirectory($directoryPath)) {
            throw new LogicException('Not a Directory');
        }

        $files = $this->file->allFiles($directoryPath);
        foreach ($files as $file) {
            $realPath = (string) $file->getRealPath();
            $filePaths[$realPath] = $realPath;
        }

        return $filePaths;
    }

    /**
     * Parse all definition Yaml files.
     *
     * @param  array  $filePaths
     * @return mixed
     */
    protected function parseAllYaml(array $filePaths): array
    {
        $yamlParseTexts = [];

        foreach ($filePaths as $filePath) {
            if (count($this->parseYaml($filePath)) >= 2) {
                throw new LogicException('Yaml data must be one data per file filePath: '.$filePath);
            }

            // Rule that there is always one data in Yaml data
            $yamlParseTexts[$filePath] = collect($this->parseYaml($filePath))->first();
        }

        return $yamlParseTexts;
    }

    /**
     * Parse Yaml files.
     *
     * @param  string  $filePath
     * @return mixed
     */
    protected function parseYaml(string $filePath)
    {
        $extension = $this->file->extension($filePath);
        if ($extension !== 'yml') {
            throw new LogicException('Could not parse because it is not Yaml data filePath: '.$filePath);
        }

        return $this->yaml::parse(file_get_contents($filePath));
    }
}

使い方

Reader.php
$yamlReader = app()->make(Reader::class);

$result = $yamlReader->readFileByDirectoryPath('yamlが保存されているディレクトリパス', ['除外したいファイル名']);

$result2 = $yamlReader->readFileByFileName('yamlが保存されているディレクトリパス', '読み込みたいファイル名');

関連