Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
5 / 5
CRAP
n/a
0 / 0
FastForward\Config\config
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
12
FastForward\Config\configCache
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
FastForward\Config\configDir
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
FastForward\Config\configProvider
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
FastForward\Config\configFile
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/**
6 * This file is part of php-fast-forward/config.
7 *
8 * This source file is subject to the license bundled
9 * with this source code in the file LICENSE.
10 *
11 * @copyright Copyright (c) 2025-2026 Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
12 * @license   https://opensource.org/licenses/MIT MIT License
13 *
14 * @see       https://github.com/php-fast-forward/config
15 * @see       https://github.com/php-fast-forward
16 * @see       https://datatracker.ietf.org/doc/html/rfc2119
17 */
18
19namespace FastForward\Config;
20
21use Psr\SimpleCache\CacheInterface;
22
23/**
24 * Creates a unified configuration object from various sources.
25 *
26 * This function SHALL normalize and aggregate mixed input types such as arrays,
27 * directories, and Laminas configuration providers into a single configuration instance.
28 *
29 * @param array|ConfigInterface|string ...$configs The configuration sources.
30 *
31 * @return ConfigInterface the aggregated configuration instance
32 */
33function config(array|ConfigInterface|string ...$configs): ConfigInterface
34{
35    foreach ($configs as $index => $config) {
36        if (\is_array($config)) {
37            $configs[$index] = new ArrayConfig($config);
38        }
39
40        if (\is_string($config) && is_dir($config) && is_readable($config)) {
41            $configs[$index] = configDir($config, true);
42        }
43
44        if (\is_string($config) && str_ends_with($config, '.php') && is_file($config)) {
45            $configs[$index] = new PhpFileConfig($config);
46        }
47
48        if (\is_string($config)
49            && class_exists($config)
50            && method_exists($config, '__invoke')
51        ) {
52            $configs[$index] = configProvider([$config]);
53        }
54    }
55
56    return new AggregateConfig(...$configs);
57}
58
59
60/**
61 * Creates a cached configuration object from various sources.
62 *
63 * This function SHALL wrap the configuration in a caching layer using PSR-16 CacheInterface.
64 *
65 * @param CacheInterface $cache the cache pool for storing configuration data
66 * @param array|ConfigInterface|string ...$configs The configuration sources.
67 *
68 * @return ConfigInterface the cached configuration instance
69 */
70function configCache(CacheInterface $cache, array|ConfigInterface|string ...$configs): ConfigInterface
71{
72    return new CachedConfig(cache: $cache, defaultConfig: config(...$configs));
73}
74
75/**
76 * Creates a directory-based configuration provider.
77 *
78 * If the recursive flag is TRUE, nested directories SHALL be included in the scan.
79 * Configuration files MUST follow the PHP file format.
80 *
81 * @param string $rootDirectory the directory to load configuration files from
82 * @param bool $recursive whether to include files in subdirectories recursively
83 * @param string|null $cachedConfigFile optional path to a cache file for the configuration
84 *
85 * @return ConfigInterface the resulting configuration provider instance
86 */
87function configDir(
88    string $rootDirectory,
89    bool $recursive = false,
90    ?string $cachedConfigFile = null,
91): ConfigInterface {
92    $configClass = $recursive
93        ? RecursiveDirectoryConfig::class
94        : DirectoryConfig::class;
95
96    return new $configClass($rootDirectory, $cachedConfigFile);
97}
98
99/**
100 * Creates a configuration from a list of Laminas-style configuration providers.
101 *
102 * Each provider MUST be invokable and return an array or configuration structure.
103 *
104 * @param iterable $providers a list of configuration providers
105 * @param string|null $cachedConfigFile optional path to a cache file for the configuration
106 *
107 * @return ConfigInterface the resulting configuration instance
108 */
109function configProvider(iterable $providers, ?string $cachedConfigFile = null): ConfigInterface
110{
111    return new LaminasConfigAggregatorConfig(providers: $providers, cachedConfigFile: $cachedConfigFile);
112}
113
114/**
115 * Creates a PHP file configuration provider.
116 *
117 * Configuration files MUST follow the PHP file format and return an array.
118 *
119 * @param string $file the path to the PHP configuration file
120 * @param bool $persistent whether changes should be saved back to the file
121 * @param array<string, mixed>|ConfigInterface|null $defaultConfig optional default configuration when the file does not exist
122 *
123 * @return ConfigInterface the resulting configuration instance
124 */
125function configFile(
126    string $file,
127    bool $persistent = false,
128    array|ConfigInterface|null $defaultConfig = null,
129): ConfigInterface {
130    return new PhpFileConfig(file: $file, persistent: $persistent, defaultConfig: $defaultConfig);
131}
132