Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.31% covered (success)
92.31%
24 / 26
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
Configuration
92.31% covered (success)
92.31%
24 / 26
66.67% covered (warning)
66.67%
2 / 3
11.06
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 load
89.47% covered (warning)
89.47%
17 / 19
0.00% covered (danger)
0.00%
0 / 1
6.04
 replace
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core\Serialization;
6
7use PeServer\Core\Collection\Arr;
8use PeServer\Core\Code;
9use PeServer\Core\IO\Directory;
10use PeServer\Core\IO\File;
11use PeServer\Core\IO\Path;
12use PeServer\Core\Text;
13use PeServer\Core\Throws\ArgumentException;
14
15/**
16 * 設定ファイルの読み込み加工処理。
17 */
18class Configuration
19{
20    #region define
21
22    public const FILE_TYPE_DEFAULT = Text::EMPTY;
23    public const FILE_TYPE_JSON = 'json';
24
25    #endregion
26
27    #region variable
28
29    /**
30     * 環境。
31     */
32    private readonly string $environment;
33
34    #endregion
35
36    /**
37     * 生成
38     *
39     * @param string $environment 環境。
40     */
41    public function __construct(string $environment)
42    {
43        $this->environment = $environment;
44    }
45
46    #region function
47
48    /**
49     * 設定ファイル読み込み。
50     *
51     * @param string $directoryPath 設定ファイル配置ディレクトリ。
52     * @param string $fileName ファイル名。
53     * @param string $fileType ファイル種別。未指定(FILE_TYPE_DEFAULT)の場合はファイル拡張子から判断する
54     * @return array<mixed>
55     */
56    public function load(string $directoryPath, string $fileName, string $fileType = self::FILE_TYPE_DEFAULT): array
57    {
58        $baseFileExtension = Path::getFileExtension($fileName, false);
59
60        $confType = $fileType;
61        if ($fileType === self::FILE_TYPE_DEFAULT) {
62            $confType = match (Text::toLower($baseFileExtension)) {
63                'json' => self::FILE_TYPE_JSON,
64                default => self::FILE_TYPE_DEFAULT,
65            };
66        }
67        // とりあえずは JSON だけ相手にする
68        if ($confType !== self::FILE_TYPE_JSON) {
69            throw new ArgumentException('$fileName');
70        }
71
72        $baseFilePath = Path::combine($directoryPath, $fileName);
73        $environmentFileName = Path::setEnvironmentName($fileName, $this->environment);
74        $environmentFilePath = Path::combine($directoryPath, $environmentFileName);
75
76        /** @var array<mixed> */
77        $configuration = [];
78
79        /** @var array<mixed> */
80        $baseConfiguration = File::readJsonFile($baseFilePath);
81        if (File::exists($environmentFilePath)) {
82            /** @var array<mixed> */
83            $environmentConfiguration = File::readJsonFile($environmentFilePath);
84            $configuration = Arr::replace($baseConfiguration, $environmentConfiguration);
85        } else {
86            $configuration = $baseConfiguration;
87        }
88
89        return $configuration;
90    }
91
92    /**
93     * 設定データの再帰的置き換え。
94     *
95     * @param array<mixed> $array 元データ。配列の値のみが置き換え対象となる。
96     * @param array<string,string> $map 置き換え設定
97     * @param non-empty-string $head 置き換え開始文字列
98     * @param non-empty-string $tail 置き換え終了文字列
99     * @return array<mixed>
100     */
101    public function replace(array $array, array $map, string $head, string $tail): array
102    {
103        foreach ($array as $key => $value) {
104            if (is_array($value)) {
105                $array[$key] = $this->replace($value, $map, $head, $tail);
106            } elseif (is_string($value)) {
107                $array[$key] = Text::replaceMap(Code::toLiteralString($value), $map, $head, $tail);
108            }
109        }
110
111        return $array;
112    }
113
114    #endregion
115}