| 1 |
<?php |
| 2 |
|
| 3 |
declare(strict_types=1); |
| 4 |
|
| 5 |
namespace Metricool\Support\Helpers\Storages; |
| 6 |
|
| 7 |
use Metricool\Support\Helpers\Storage; |
| 8 |
use Metricool\Support\Helpers\DeferredObject; |
| 9 |
|
| 10 |
/** |
| 11 |
* General config helper used in DI container. |
| 12 |
* |
| 13 |
* @mixin Storage This class acts as a proxy to Storage. All method calls are |
| 14 |
* resolved dynamically through {@see DeferredObject::__get()} |
| 15 |
*/ |
| 16 |
final class GeneralConfig extends DeferredObject |
| 17 |
{ |
| 18 |
private array $filesToSkip = [ |
| 19 |
'env', // EnvironmentConfig |
| 20 |
'middleware', // MiddlewareConfig |
| 21 |
'user_settings', // UserSettingsConfig |
| 22 |
'languages', // LanguagesConfig |
| 23 |
]; |
| 24 |
|
| 25 |
/** |
| 26 |
* @inheritDoc |
| 27 |
*/ |
| 28 |
protected function deferredClassString(): string |
| 29 |
{ |
| 30 |
return Storage::class; |
| 31 |
} |
| 32 |
|
| 33 |
/** |
| 34 |
* @inheritDoc |
| 35 |
*/ |
| 36 |
protected function deferredConstructArguments(): array |
| 37 |
{ |
| 38 |
return [ |
| 39 |
$this->storageFromPath(dirname(__FILE__, 5) . '/config', $this->filesToSkip, true), |
| 40 |
]; |
| 41 |
} |
| 42 |
|
| 43 |
/** |
| 44 |
* Return all config files as GeneralConfig. If path is a directory, it will |
| 45 |
* merge all the files in the directory. |
| 46 |
* |
| 47 |
* @param bool $prefixWithFileName Can be used to prefix the keys with the |
| 48 |
* filename when loading a directory. Can be useful to bundle the config |
| 49 |
* data of a file under the filename which makes it easier to retrieve a |
| 50 |
* single fields config. |
| 51 |
* |
| 52 |
* @throws \InvalidArgumentException |
| 53 |
*/ |
| 54 |
private function storageFromPath(string $path, array $skip = [], bool $prefixWithFileName = false): array |
| 55 |
{ |
| 56 |
if (!file_exists($path)) { |
| 57 |
throw new \InvalidArgumentException( |
| 58 |
'Unloadable configuration file ' . esc_html($path) . ' provided.' |
| 59 |
); |
| 60 |
} |
| 61 |
|
| 62 |
$data = []; |
| 63 |
|
| 64 |
if (is_dir($path)) { |
| 65 |
$root = rtrim((string) realpath($path), DIRECTORY_SEPARATOR); |
| 66 |
|
| 67 |
// Also loads files in nested dirs. |
| 68 |
$iterator = new \RecursiveIteratorIterator( |
| 69 |
new \RecursiveDirectoryIterator($root, \FilesystemIterator::SKIP_DOTS) |
| 70 |
); |
| 71 |
|
| 72 |
/** @var \SplFileInfo $file */ |
| 73 |
foreach ($iterator as $file) { |
| 74 |
if (!$file->isFile() || in_array($file->getBasename('.php'), $skip)) { |
| 75 |
continue; |
| 76 |
} |
| 77 |
|
| 78 |
$pathname = $file->getPathname(); |
| 79 |
$extension = strtolower((string) pathinfo($pathname, PATHINFO_EXTENSION)); |
| 80 |
|
| 81 |
if ($extension !== 'php') { |
| 82 |
continue; |
| 83 |
} |
| 84 |
|
| 85 |
$fileData = require $pathname; |
| 86 |
if (!is_array($fileData)) { |
| 87 |
continue; |
| 88 |
} |
| 89 |
|
| 90 |
$fileName = (string) pathinfo($pathname, PATHINFO_FILENAME); |
| 91 |
$fileDirPath = $file->getPath(); |
| 92 |
|
| 93 |
// Compute the directory relative to the root and take the last |
| 94 |
// segment as the prefix. |
| 95 |
$relativeDir = ltrim(substr($fileDirPath, strlen($root)), DIRECTORY_SEPARATOR); |
| 96 |
$dirKey = ($relativeDir !== '' ? basename($relativeDir) : null); |
| 97 |
|
| 98 |
if ($prefixWithFileName) { |
| 99 |
if ($dirKey !== null) { |
| 100 |
// Group by immediate subdirectory, then filename. Deep |
| 101 |
// merge so multiple files in the same subdir accumulate |
| 102 |
$data[$dirKey] = array_replace_recursive( |
| 103 |
$data[$dirKey] ?? [], |
| 104 |
[$fileName => $fileData] |
| 105 |
); |
| 106 |
} else { |
| 107 |
// Top-level files keyed by filename. |
| 108 |
$data = array_replace_recursive($data, [ |
| 109 |
$fileName => $fileData |
| 110 |
]); |
| 111 |
} |
| 112 |
} else { |
| 113 |
// No prefixing: merge raw file data (deep) to avoid losing |
| 114 |
// previously merged keys. |
| 115 |
$data = array_replace_recursive($data, $fileData); |
| 116 |
} |
| 117 |
} |
| 118 |
} else { |
| 119 |
$loaded = require $path; |
| 120 |
if (is_array($loaded)) { |
| 121 |
$data = $loaded; |
| 122 |
} |
| 123 |
} |
| 124 |
|
| 125 |
return $data; |
| 126 |
} |
| 127 |
} |
| 128 |
|