diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 73008ee..7342612 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -3,7 +3,7 @@ on: release: types: [published] jobs: - build-documentation: + build_documentation: runs-on: ubuntu-latest steps: - name: Checkout @@ -15,5 +15,43 @@ jobs: architecture: 'x64' - name: Install dependencies run: python -m pip install --upgrade pip mkdocs mkdocs-material - - name: Deploy documentation - run: mkdocs gh-deploy --force \ No newline at end of file + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: docs-artifact + path: _site/ + build_api: + needs: build_documentation + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + coverage: none + - name: Install composer dependencies + uses: ramsey/composer-install@v3 + with: + composer-options: "--prefer-dist --optimize-autoloader" + - name: Download phpDocumentor phar archive + run: wget https://phpdoc.org/phpDocumentor.phar + - name: Build the coumentation api + run: php phpDocumentor.phar + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: api-artifact + path: _site/api/ + deploy_documentation: + needs: [build_documentation,build_api] + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + - name: Deploy documentation to Github Pages + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./_site diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7857d7b..7c7a4ee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: fail-fast: false matrix: operating-system: [ubuntu-latest, windows-latest, macOS-latest] - php-versions: ['8.2', '8.3'] + php-versions: ['8.3', '8.4'] symfony-version: ['6.4', '7.1'] runs-on: ${{ matrix.operating-system }} steps: @@ -32,8 +32,10 @@ jobs: with: composer-options: "--prefer-dist --optimize-autoloader" - name: Check coding standard + if: matrix.php-versions != '8.4' run: composer cs:check - name: Static analysis tool + if: matrix.php-versions != '8.4' run: composer analytics - name: Test suite run: composer test diff --git a/.gitignore b/.gitignore index a64fced..40a2698 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ composer.phar composer.lock coverage/ vendor/ +_site/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d0b46b..0eac6d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,29 @@ All notable changes to `susina/config-builder` project will be documented in thi The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### [1.1] - 2025-05-22 +### Added +- Add `replaces` option to inject an external parameter to resolve. Useful, i.e. to pass +`kernel_dir` or other parameters. +- Add [phpdocumentor](https://phpdoc.org/) to generate the documentation api +### Changed +- Update the documentation + +## [1.0.1] - 2024-11-30 +### Fixed +- Remove PHP 8.4 deprecations + +## [1.0] - 2024-09-16 +### Added +- Introduce `susina/param-resolver` library +- Introduce `susina/xml-to-array` library +### Changed +- Bump dependencies +- Update Github Actions +- Update documentation +### Removed +- Remove `.ini` support since it's not suited for complex nested configurations + ## [0.4] - 2023-02-16 ### Added - `ConfigBuilder::keepFirstXmlTag` method, to include into the configuration array also the first xml tag diff --git a/docs/methods.md b/docs/methods.md deleted file mode 100644 index 4f8f86b..0000000 --- a/docs/methods.md +++ /dev/null @@ -1,261 +0,0 @@ -The Configuration Builder class can be set up via the following methods: - -## addFile - -!!! Example "Signature" - `#!php-inline public function addFile(string|SplFileInfo ...$files): self` - -The parameters can contain: - -- the name of the configuration file to load -- the full path name of the configuration file to load -- SplFileInfo object representing the configuration file to load - - -Use this method to add one or more elements to the list of configuration files to load. I.e.: - -```php -addFile('my-project-config.yaml.dist', 'my-project-config-yml'); -``` - - -## setFiles - -!!! example "Signature" - `#!php-inline public function setFiles(array|IteratorAggregate $files): self` - -This method receive an array of strings or SplFileInfo objects and set the list of the configuration files to load. -This method __removes__ all the files previously added. - -```php -setFiles($configFiles); -``` - -This method can also accept an iterator, containing strings or SplFileInfo, so you can pass also an instance of a finder object, i.e. [Symfony Finder](https://symfony.com/doc/current/components/finder.html): - -```php -in('app/config')->name('*.json')->files(); - -$builder->setFiles($finder); -``` - - -## addDirectory - -!!! example "Signature" - `#!php-inline public function addDirectory(string|SplFileInfo ...$dirs): self` - -Add one or more directories where to find the configuration files. - -The parameters can contain: - -- the full path name of the directory -- SplFileInfo object representing a directory where to find the configuration files - -This method check if the passed directories are existent and readable, otherwise throws a `ConfigurationBuilderException`. - - -```php -addDirectory(__DIR__ . '/app/config', getcwd()); -``` - - -## setDirectories - -!!! example "Signature" - `#!php-inline public function setDirectories(array|IteratorAggregate $dirs): self` - -This method receive an array of strings or SplFileInfo objects and set the list of the directories where to find the configuration files to load. -This method __removes__ all the directory previously added. - -```php -setDirectories($dirs); -``` - -This method can also accept an iterator, containing strings or SplFileInfo, so you can pass also an instance of a finder object, i.e. [Symfony Finder](https://symfony.com/doc/current/components/finder.html): - -```php -in(getcwd())->name('config')->directories(); - -$builder->setDirectories($dirs); -``` - - -## setDefinition - -!!! example "Signature" - `#!php-inline public function setDefinition(ConfigurationInterface $definition): self` - -Add an instance of `Symfony\Component\Config\Definition\ConfigurationInterface` to process the configuration parameters. - -For further information about Symfony Config and how to define a `ConfigurationInterface` class, please see the [official Symfony documentation](https://symfony.com/doc/current/components/config/definition.html). - - -## setConfigurationClass - -!!! example "Signature" - `#!php-inline public function setConfigurationClass(string $configurationClass): self` - -Set the configuration class to populate with the processed parameters. If the class does not exist, a `ConfigurationBuilderException` is thrown. -The method expects to pass an array of parameters to the class constructor. - - -## setInitMethod - -!!! example "Signature" - `#!php-inline public function setInitMethod(string $initMethod): self` - -The configuration class, set via [setConfigurationClass](#set-configuration-class) method, could be populated via its constructor or via an _initialization_ method, expecting an array as parameter. -With `setInitMethod` we set the method to use to populate the configuration class. - - -Suppose you have a configuration class, like the following: - -```php -setConfigurationClass(ConfigurationManager::class) - ->setInitMethod('setParameters') - ; -``` - - -## setBeforeParams - -!!! example "Signature" - `#!php-inline public function setBeforeParams(array $beforeParams): self` - -Set an array of parameters to merge into your configuration __before__ loading the files. - -Note that the value of this parameters _could be overwritten_ by the ones loaded from the configuration files. - - -## setAfterParams - -!!! example "Signature" - `#!php-inline public function setAfterParams(array $afterParams): self` - -Set an array of parameters to merge into your configuration __after__ loading the files. - -Note that the value of this parameters _could overwrite_ the ones loaded from the configuration files. - -## setCacheDirectory - -!!! example "Signature" - `#!php-inline public function setCacheDirectory(string $cache): self` - -Set the directory where to save the cache files (see [Cache](usage.md#cache)). - -## populateContainer - -!!! example "Signature" -`#!php-inline public function populateContainer(object $container, string $method): void` - -Populate a dependency injection container `$container` with the loaded configuration parameters. -You can retrieve each parameter with a _dot acces_ key (i.e. database.connection.dsn). - -## keepFirstXmlTag - -!!! example "Signature" -`#!php-inline public function keepFirstXmlTag(bool $keep = true): self` - -When loading XML files, keep the first xml tag as part of the configuration. - -Consider the following xml: - -```xml - - - bar - baz - -``` - -it usually results in the following array: - -```php - 'bar', - 'bar' => 'baz' - ]; -``` - -If you call `keepFirstXmTag` then the resulted array is the following: - -```php - [ - 'foo' => 'bar', - 'bar' => 'baz' - ] - ]; -``` diff --git a/docs/usage.md b/docs/usage.md index 2ae107c..7e29b51 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -23,7 +23,7 @@ $builder = ConfigurationBuilder::create() ; ``` -You can set up the `ConfigurationBuilder` via all the methods explained into [Api Reference](methods.md) document. +You can set up the `ConfigurationBuilder` via all the methods explained into [Api Reference](api/index.html) document. ## Get The Configuration as an Array diff --git a/mkdocs.yml b/mkdocs.yml index f3506c3..7f44dd3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,6 +12,7 @@ edit_uri: '' copyright: 'Susina Configuration Builder is licensed under Apache 2.0 license' #Configuration +site_dir: _site theme: name: material favicon: assets/hammer-and-wrench.png @@ -28,7 +29,7 @@ nav: - Installation: installation.md - Usage: usage.md - Reference: - - Api: methods.md + - Api: api/index.html - Parameters reference: parameters.md - Complete Example: example.md - About: diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml new file mode 100644 index 0000000..7a8c4f0 --- /dev/null +++ b/phpdoc.dist.xml @@ -0,0 +1,20 @@ + + + + _site/api + _site/cache + + + + + src + + + + + \ No newline at end of file diff --git a/src/ConfigCache.php b/src/ConfigCache.php index 3456418..7eb8278 100644 --- a/src/ConfigCache.php +++ b/src/ConfigCache.php @@ -10,11 +10,22 @@ use Symfony\Component\Config\ConfigCache as BaseConfigCache; +/** + * Specialized class to cache the built configuration. + * It extends `Symfony\Component\Config\ConfigCache` class. + * + * @author Cristiano Cinotti + */ class ConfigCache extends BaseConfigCache { private string $builderSerial; private string $serialFile; + /** + * @param string $file The cache file. + * @param bool $debug start/stop debug environment. + * @param ConfigurationBuilder $builder The object to save in cache. + */ public function __construct(string $file, bool $debug, ConfigurationBuilder $builder) { parent::__construct($file, $debug); @@ -23,6 +34,11 @@ public function __construct(string $file, bool $debug, ConfigurationBuilder $bui $this->serialFile = dirname($this->getPath()) . DIRECTORY_SEPARATOR . 'config_builder.serial'; } + /** + * Check if the cache is fresh. + * + * @return bool + */ public function isFresh(): bool { if (!file_exists($this->serialFile) || $this->builderSerial !== file_get_contents($this->serialFile)) { @@ -32,6 +48,12 @@ public function isFresh(): bool return parent::isFresh(); } + /** + * Write the data into the cache. + * + * @param $content The content to write in cache. + * @param $metadata An optional array of metadata. + */ public function write(string $content, ?array $metadata = null): void { parent::write($content, $metadata); diff --git a/src/ConfigurationBuilder.php b/src/ConfigurationBuilder.php index 7cfdbf3..dbb7d99 100644 --- a/src/ConfigurationBuilder.php +++ b/src/ConfigurationBuilder.php @@ -11,20 +11,28 @@ use IteratorAggregate; use SplFileInfo; use Susina\ConfigBuilder\Exception\ConfigurationBuilderException; -use Susina\ConfigBuilder\Loader\IniFileLoader; use Susina\ConfigBuilder\Loader\JsonFileLoader; use Susina\ConfigBuilder\Loader\NeonFileLoader; use Susina\ConfigBuilder\Loader\PhpFileLoader; use Susina\ConfigBuilder\Loader\XmlFileLoader; use Susina\ConfigBuilder\Loader\YamlFileLoader; +use Susina\ParamResolver\ParamResolver; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\Processor; use Symfony\Component\Config\Loader\DelegatingLoader; use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\Config\Resource\FileResource; +/** + * Class ConfigurationBuilder. + * + * @author Cristiano Cinotti + */ final class ConfigurationBuilder { + /** + * @var string The name of the cache file. + */ public const CACHE_FILE = 'susina_config_builder.cache'; /** @@ -33,7 +41,7 @@ final class ConfigurationBuilder private array $files = []; /** - * @var array The directories where to find the configuration files. + * @var string[] The directories where to find the configuration files. */ private array $directories = []; @@ -54,19 +62,27 @@ final class ConfigurationBuilder private string $initMethod = ''; /** - * @var array Additional array of parameters to merge BEFORE to load the configuration files. + * @var array Additional array of parameters to merge BEFORE loading the configuration files. */ private array $beforeParams = []; /** - * @var array Additional array of parameters to merge AFTER to load the configuration files. + * @var array Additional array of parameters to merge AFTER loading the configuration files. */ private array $afterParams = []; + /** + * @var array An array of key => values elements to replace into the configuration, before parameters resolving and validating. + */ + private array $replaces = []; + + /** + * @string The cache directory. + */ private string $cacheDirectory = ''; /** - * @var bool if keep the first xml tag in an xml configuration file + * @var bool If keep the first xml tag in an xml configuration file. */ private bool $keepFirstXmlTag = false; @@ -83,8 +99,22 @@ public static function create(): self /** * Add one or more file names to the array of configuration files to load. * - * @param string|SplFileInfo ...$files + * The parameters can contain: + * - the name of the configuration file to load + * - the full path name of the configuration file to load + * - SplFileInfo object representing the configuration file to load + * + * Use this method to add one or more elements to the list of configuration files to load. I.e.: + * ```php + * addFile('my-project-config.yaml.dist', 'my-project-config-yml'); + * ``` * + * @param string|SplFileInfo ...$files The files to load. * @return $this */ public function addFile(string|SplFileInfo ...$files): self @@ -102,11 +132,37 @@ public function addFile(string|SplFileInfo ...$files): self /** * Set the name of the configuration files to load. - * It accepts also an Iterator, so that It's possible to directly pass the result of a finder library - * (e.g. Symfony Finder) * - * @param array|IteratorAggregate $files + * This method receives an array of strings or SplFileInfo objects and sets the list of the configuration files to load. + * It __removes__ all the files previously added. * + * ```php + * setFiles($configFiles); + * ``` + * + * This method can also accept an iterator, containing strings or SplFileInfo, + * so you can pass also an instance of a finder object, i.e. [Symfony Finder](https://symfony.com/doc/current/components/finder.html): + * + * ```php + * in('app/config')->name('*.json')->files(); + * + * $builder->setFiles($finder); + * ``` + * + * @param array|IteratorAggregate $files The files to add. * @return $this */ public function setFiles(array|IteratorAggregate $files): self @@ -122,10 +178,27 @@ public function setFiles(array|IteratorAggregate $files): self /** * Add one or more directories where to find the configuration files. * - * @param string|SplFileInfo ...$dirs + * Add one or more directories where to find the configuration files. + * The parameters can contain: + * + * - the full path name of the directory + * - SplFileInfo object representing a directory where to find the configuration files + * + * This method check if the passed directories are existent and readable, + * otherwise throws a `ConfigurationBuilderException`. * + * ```php + * addDirectory(__DIR__ . '/app/config', getcwd()); + * ``` + * + * @param string|SplFileInfo ...$dirs The directories to add. * @return $this - * @throws ConfigurationBuilderException + * @throws ConfigurationBuilderException If a directory does not exist or it's not writeable. */ public function addDirectory(string|SplFileInfo ...$dirs): self { @@ -151,14 +224,40 @@ function (string|SplFileInfo $dir): string { } /** - * Set the name of the directory where to find the configuration files to load. - * It accepts also an Iterator, so that It's possible to directly pass the result of a finder library - * (e.g. Symfony Finder) + * Set the name of the directories where to find the configuration files to load. + * + * This method receives an array of strings or SplFileInfo objects and sets the list of the directories + * where to find the configuration files to load. It __removes__ all the previously added directories. + * + * ```php + * setDirectories($dirs); + * ``` + * + * This method can also accept an iterator, containing strings or SplFileInfo, + * so you can pass also an instance of a finder object, i.e. [Symfony Finder](https://symfony.com/doc/current/components/finder.html): + * + * ```php + * in(getcwd())->name('config')->directories(); * - * @param array|IteratorAggregate $dirs + * $builder->setDirectories($dirs); + * ``` * + * @param array|IteratorAggregate $dirs Se the entire directories array. * @return $this - * @throws ConfigurationBuilderException + * @throws ConfigurationBuilderException If a directory does not exist or it's not writeable. */ public function setDirectories(array|IteratorAggregate $dirs): self { @@ -173,8 +272,11 @@ public function setDirectories(array|IteratorAggregate $dirs): self /** * Set the object to process the configuration parameters. * - * @param ConfigurationInterface $definition + * Add an instance of `Symfony\Component\Config\Definition\ConfigurationInterface` to process the configuration parameters. + * For further information about Symfony Config and how to define a `ConfigurationInterface` class, + * please see the [official Symfony documentation](https://symfony.com/doc/current/components/config/definition.html). * + * @param ConfigurationInterface $definition The configuration definition object. * @return $this * @see https://symfony.com/doc/current/components/config/definition.html */ @@ -188,10 +290,13 @@ public function setDefinition(ConfigurationInterface $definition): self /** * Set the full class name of the configuration object to instantiate. * - * @param string $configurationClass + * Set the configuration class to populate with the processed parameters. If the class does not exist, + * a `ConfigurationBuilderException` is thrown. This method expects to pass an array of parameters to the class constructor. + * + * @param string $configurationClass The configuration full classname. * * @return $this - * @throws ConfigurationBuilderException + * @throws ConfigurationBuilderException If the class does not exist. */ public function setConfigurationClass(string $configurationClass): self { @@ -206,8 +311,44 @@ public function setConfigurationClass(string $configurationClass): self /** * Set the method to use to initialize the configuration object. * - * @param string $initMethod + * The configuration class, set via [setConfigurationClass](#set-configuration-class) method, could be populated + * via its constructor or via an _initialization_ method, expecting an array as parameter. + * With `setInitMethod` we set the method to use to populate the configuration class. + * + * Suppose you have a configuration class, like the following: + * + * ```php + * setConfigurationClass(ConfigurationManager::class) + * ->setInitMethod('setParameters'); + * ``` * + * @param string $initMethod The name of the method. * @return $this */ public function setInitMethod(string $initMethod): self @@ -220,8 +361,13 @@ public function setInitMethod(string $initMethod): self /** * Set an array of additional parameters to merge before loading the configuration files. * - * @param array $beforeParams + * Set an array of parameters to merge into your configuration __before__ loading the files. + * These parameters are processed and validated via Symfony\Config, so they must be compatible with + * the definition class specified in `$definition` property. * + * > The value of these parameters __could be overwritten__ by the ones loaded from the configuration files. + * + * @param array $beforeParams The array of parameters to be merged. * @return $this */ public function setBeforeParams(array $beforeParams): self @@ -234,8 +380,13 @@ public function setBeforeParams(array $beforeParams): self /** * Set an array of additional parameters to merge after loading the configuration files. * - * @param array $afterParams + * Set an array of parameters to merge into your configuration __after__ loading the files. + * These parameters are processed and validated via Symfony\Config, so they must be compatible with + * the definition class specified in `$definition` property. + * + * > The value of these parameters __could overwrite__ the ones loaded from the configuration files. * + * @param array $afterParams The array of parameters to be merged. * @return $this */ public function setAfterParams(array $afterParams): self @@ -249,7 +400,7 @@ public function setAfterParams(array $afterParams): self * Set the cache directory or the CacheInterface object * * @return $this - * @throws ConfigurationBuilderException + * @throws ConfigurationBuilderException If the directory does not exist or it's not readable. */ public function setCacheDirectory(string $cache): self { @@ -264,11 +415,82 @@ public function setCacheDirectory(string $cache): self return $this; } + /** + * Set an array of parameters to replace. + * + * This values are useful for parameters replacing and they're removed before processing and validating + * the configuration. In this way, you can write some "standard" parameters in your configuration. I.e.: + * + * ```yaml + * cache: + * path: %kernel_dir%/cache/my_app.cache + * ``` + * + * Now,you can inject the `kernel_dir` parameter to replace it: + * + * ```php + * setReplaces(['kernel_dir' => '/my/absolute/path]) + * ->getConfigurationArray(); + * + * // $config = [ + * // 'cache' => [ + * // 'path' => '/my/absolute/path/my_app.cache' + * // ] + * //] + * ``` + * + * Note that, after replacing, the `kernel_dir` parameter is removed from the configuration. + * + * @param array $params The parameters to replace + * @return $this + */ + public function setReplaces(array $params): self + { + $this->replaces = $params; + + return $this; + } + /** * Keep also the first tag of a xml configuration. * - * @param bool $keep + * When loading XML files, it keeps the first xml tag as part of the configuration. Consider the following xml: + * + * ```xml + * + * + * bar + * baz + * + * ``` * + * it usually results in the following array: + * ```php + * 'bar', + * 'bar' => 'baz' + * ]; + * ``` + * + * If you call `keepFirstXmTag` then the resulted array is the following: + * + * ```php + * [ + * 'foo' => 'bar', + * 'bar' => 'baz' + * ] + * ]; + * ``` + * + * @param bool $keep * @return $this */ public function keepFirstXmlTag(bool $keep = true): self @@ -282,6 +504,7 @@ public function keepFirstXmlTag(bool $keep = true): self * Return a populated configuration object. * * @return object + * @throws ConfigurationBuilderException If not set any configuration classtoinstantiate. */ public function getConfiguration(): object { @@ -316,10 +539,11 @@ public function getConfigurationArray(): array /** * Populate a container object with the configuration values. * - * @param object $container The container object - * @param string $method The container method to add a parameter - * (i.e. `set` for Php-Di or `setParameter` for Symfony Dependency Injection). + * This method populates a dependency injection container `$container` with the loaded configuration parameters. + * You can acces the loaded parameters _dot acces_ key reference (i.e. database.connection.dsn). * + * @param object $container The container object + * @param string $method The container method to add a parameter (i.e. `set` for Php-Di or `setParameter` for Symfony Dependency Injection). * @return void */ public function populateContainer(object $container, string $method): void @@ -331,6 +555,14 @@ public function populateContainer(object $container, string $method): void array_map([$container, $method], array_keys($parameters), array_values($parameters)); } + /** + * Transform an array in dotted notation. + * Useful to populate a di-container. + * + * @param array $parameters The array to translate in dotted notation. + * @param array &$output The array to return. + * @param string $affix The optional affix to add to the dotted key. + */ private function getDotArray(array $parameters, array &$output, string $keyAffix = ''): void { foreach ($parameters as $key => $value) { @@ -344,6 +576,8 @@ private function getDotArray(array $parameters, array &$output, string $keyAffix } /** + * Load parameters from the configuration files. + * * @psalm-suppress NamedArgumentNotAllowed */ private function loadParameters(): array @@ -358,9 +592,29 @@ private function loadParameters(): array ]); $delegatingLoader = new DelegatingLoader($loaderResolver); - return array_merge_recursive(...array_map([$delegatingLoader, 'load'], $this->files)); + $parameters = array_merge_recursive(...array_map([$delegatingLoader, 'load'], $this->files)); + + //Add replaces to the array... + foreach ($this->replaces as $key => $value) { + $parameters[$key] = $value; + } + + //Param resolver do the job... + $parameters = ParamResolver::create()->resolve($parameters); + + //Remove replaces from the array. + foreach ($this->replaces as $key => $value) { + unset($parameters[$key]); + } + + return $parameters; } + /** + * Process and validate the configuration. + * + * @throws ConfigurationBuilderException If the definition file is not set. + */ private function loadConfiguration(): array { $processor = new Processor(); @@ -376,7 +630,9 @@ private function loadConfiguration(): array } /** - * @return array + * Load the configuration from cache. + * + * @return array The configuration * * @psalm-suppress PossiblyInvalidArgument FileLocator::locate() returns a string * if the 3rd function argument is not set to false diff --git a/src/Exception/ConfigurationBuilderException.php b/src/Exception/ConfigurationBuilderException.php index 8e81958..65040d0 100644 --- a/src/Exception/ConfigurationBuilderException.php +++ b/src/Exception/ConfigurationBuilderException.php @@ -10,6 +10,10 @@ use RuntimeException; +/** + * Class ConfigurationBuilderException. + * Specialized Exception class for Configuration Builder. + */ class ConfigurationBuilderException extends RuntimeException { } diff --git a/src/FileLocator.php b/src/FileLocator.php index e85fea7..334305b 100644 --- a/src/FileLocator.php +++ b/src/FileLocator.php @@ -11,8 +11,18 @@ use Susina\ConfigBuilder\Exception\ConfigurationBuilderException; use Symfony\Component\Config\FileLocator as BaseFileLocator; +/** + * Class to locate the configuration files to load. + * + * @author Cristiano Cinotti + */ class FileLocator extends BaseFileLocator { + /** + * @inheritdoc + * + * @throws ConfigurationBuilderException If the located files are not readable. + */ public function locate(string $name, ?string $currentPath = null, bool $first = true): string|array { $output = parent::locate($name, $currentPath, $first); diff --git a/src/Loader/JsonFileLoader.php b/src/Loader/JsonFileLoader.php index 7e69df1..c80fe09 100644 --- a/src/Loader/JsonFileLoader.php +++ b/src/Loader/JsonFileLoader.php @@ -8,22 +8,20 @@ namespace Susina\ConfigBuilder\Loader; -use Susina\ParamResolver\ParamResolver; use Symfony\Component\Config\Loader\FileLoader; /** * JsonFileLoader loads configuration parameters from json file. * - * @author Cristiano Cinotti + * @author Cristiano Cinotti */ class JsonFileLoader extends FileLoader { /** * Loads a Json file. * - * @param mixed $resource The resource + * @param mixed $resource The resource to load. * @param string|null $type The resource type - * * @return array * @throws \JsonException * @@ -36,9 +34,7 @@ public function load(mixed $resource, ?string $type = null): array return []; } - $content = json_decode($json, true, 512, JSON_THROW_ON_ERROR); - - return ParamResolver::create()->resolve($content); //Resolve parameter placeholders (%name%) + return json_decode($json, true, 512, JSON_THROW_ON_ERROR); } /** @@ -46,8 +42,7 @@ public function load(mixed $resource, ?string $type = null): array * * @param mixed $resource A resource * @param string|null $type The resource type - * - * @return bool true if this class supports the given resource, false otherwise + * @return bool true If this class supports the given resource, false otherwise */ public function supports($resource, $type = null): bool { diff --git a/src/Loader/NeonFileLoader.php b/src/Loader/NeonFileLoader.php index 4e33032..dcfae3d 100644 --- a/src/Loader/NeonFileLoader.php +++ b/src/Loader/NeonFileLoader.php @@ -9,7 +9,6 @@ namespace Susina\ConfigBuilder\Loader; use Nette\Neon\Neon; -use Susina\ParamResolver\ParamResolver; use Symfony\Component\Config\Loader\FileLoader; /** @@ -20,11 +19,10 @@ class NeonFileLoader extends FileLoader { /** - * Loads a Yaml file. - * - * @param mixed $resource The resource - * @param string|null $type The resource type + * Loads a Neon file. * + * @param mixed $resource The resource to load. + * @param string|null $type The resource type. * @return array * * @psalm-suppress PossiblyInvalidArgument FileLocator::locate() returns string, since 3rd argument isn't false @@ -33,17 +31,15 @@ public function load(mixed $resource, ?string $type = null): array { $content = Neon::decode(file_get_contents($this->getLocator()->locate($resource))); - return $content === null ? [] : ParamResolver::create()->resolve($content); + return $content ?? []; } /** * Returns true if this class supports the given resource. - * Both 'yml' and 'yaml' extensions are accepted. - * - * @param mixed $resource A resource - * @param string|null $type The resource type * - * @return bool true if this class supports the given resource, false otherwise + * @param mixed $resource A resource. + * @param string|null $type The resource type. + * @return bool true If this class supports the given resource, false otherwise. */ public function supports($resource, $type = null): bool { diff --git a/src/Loader/PhpFileLoader.php b/src/Loader/PhpFileLoader.php index d7f18da..27a19b4 100644 --- a/src/Loader/PhpFileLoader.php +++ b/src/Loader/PhpFileLoader.php @@ -9,7 +9,6 @@ namespace Susina\ConfigBuilder\Loader; use Susina\ConfigBuilder\Exception\ConfigurationBuilderException; -use Susina\ParamResolver\ParamResolver; use Symfony\Component\Config\Loader\FileLoader; /** @@ -24,17 +23,15 @@ * ); * * - * @author Cristiano Cinotti + * @author Cristiano Cinotti */ class PhpFileLoader extends FileLoader { /** * Loads a PHP file. * - * @param mixed $resource The resource - * @param string|null $type The resource type - * - * + * @param mixed $resource The resource to load. + * @param string|null $type The resource type. * @return array * @throws ConfigurationBuilderException * @@ -60,17 +57,16 @@ public function load(mixed $resource, ?string $type = null): array throw new ConfigurationBuilderException("The configuration file '$resource' has invalid content."); } - return ParamResolver::create()->resolve($content); //Resolve parameter placeholders (%name%) + return $content; } /** * Returns true if this class supports the given resource. * It supports both .php and .inc extensions. * - * @param mixed $resource A resource - * @param string|null $type The resource type - * - * @return bool true if this class supports the given resource, false otherwise + * @param mixed $resource A resource. + * @param string|null $type The resource type. + * @return bool true if this class supports the given resource, false otherwise. */ public function supports(mixed $resource, $type = null): bool { diff --git a/src/Loader/XmlFileLoader.php b/src/Loader/XmlFileLoader.php index c806e16..fde8846 100644 --- a/src/Loader/XmlFileLoader.php +++ b/src/Loader/XmlFileLoader.php @@ -9,15 +9,15 @@ namespace Susina\ConfigBuilder\Loader; use Susina\ConfigBuilder\Exception\ConfigurationBuilderException; -use Susina\ParamResolver\ParamResolver; use Susina\XmlToArray\Converter; +use Susina\XmlToArray\Exception\ConverterException; use Symfony\Component\Config\FileLocatorInterface; use Symfony\Component\Config\Loader\FileLoader; /** * XmlFileLoader loads configuration parameters from xml file. * - * @author Cristiano Cinotti + * @author Cristiano Cinotti */ class XmlFileLoader extends FileLoader { @@ -32,13 +32,11 @@ public function __construct(FileLocatorInterface $fileLocator, bool $keepFirstTa /** * Loads a Xml file. * - * @param mixed $resource The resource - * @param string|null $type The resource type - * + * @param mixed $resource The resource to load. + * @param string|null $type The resource type. * @return array - * - * @throws ConfigurationBuilderException - * @throws ConfigurationBuilderException + * @throws ConverterException If an error occurs while parsing the xml. + * @throws ConfigurationBuilderException If an error occurs while reading the xml file. * * @psalm-suppress PossiblyInvalidArgument FileLocator::locate() returns string, since 3rd argument isn't false */ @@ -51,18 +49,16 @@ public function load(mixed $resource, ?string $type = null): array } $converter = new Converter(['preserveFirstTag' => $this->keepFirstTag]); - $content = $converter->convert($xmlContent); - return ParamResolver::create()->resolve($content); //Resolve parameter placeholders (%name%) + return $converter->convert($xmlContent); } /** * Returns true if this class supports the given resource. * - * @param mixed $resource A resource - * @param string|null $type The resource type - * - * @return bool true if this class supports the given resource, false otherwise + * @param mixed $resource A resource. + * @param string|null $type The resource type. + * @return bool true If this class supports the given resource, false otherwise. */ public function supports(mixed $resource, ?string $type = null): bool { diff --git a/src/Loader/YamlFileLoader.php b/src/Loader/YamlFileLoader.php index 3594121..358199f 100644 --- a/src/Loader/YamlFileLoader.php +++ b/src/Loader/YamlFileLoader.php @@ -9,7 +9,6 @@ namespace Susina\ConfigBuilder\Loader; use Susina\ConfigBuilder\Exception\ConfigurationBuilderException; -use Susina\ParamResolver\ParamResolver; use Symfony\Component\Config\Loader\FileLoader; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Yaml; @@ -17,7 +16,7 @@ /** * YamlFileLoader loads configuration parameters from yaml file. * - * @author Cristiano Cinotti + * @author Cristiano Cinotti */ class YamlFileLoader extends FileLoader { @@ -26,11 +25,9 @@ class YamlFileLoader extends FileLoader * * @param mixed $resource The resource * @param string|null $type The resource type - * * @return array - * - * @throws ConfigurationBuilderException - * @throws ParseException if something goes wrong in parsing file + * @throws ConfigurationBuilderException If an error occurs while reading the file. + * @throws ParseException If something goes wrong in parsing the file. * * @psalm-suppress PossiblyInvalidArgument FileLocator::locate() returns string, since 3rd argument isn't false */ @@ -46,17 +43,16 @@ public function load(mixed $resource, ?string $type = null): array throw new ConfigurationBuilderException('Unable to parse the configuration file: wrong yaml content.'); } - return ParamResolver::create()->resolve($content); + return $content; } /** * Returns true if this class supports the given resource. * Both 'yml' and 'yaml' extensions are accepted. * - * @param mixed $resource A resource - * @param string|null $type The resource type - * - * @return bool true if this class supports the given resource, false otherwise + * @param mixed $resource A resource. + * @param string|null $type The resource type. + * @return bool true If this class supports the given resource, false otherwise. */ public function supports($resource, $type = null): bool { diff --git a/tests/Functional/FunctionalTest.php b/tests/Functional/FunctionalTest.php index 2af05a3..bbcc8f2 100644 --- a/tests/Functional/FunctionalTest.php +++ b/tests/Functional/FunctionalTest.php @@ -255,3 +255,51 @@ ] ); }); + +test('Replaces', function () { + $file = vfsStream::newFile('config.yml')->at($this->getRoot())->setContent(<< true, + 'default_connection' => 'mysql', + 'connections' => [ + 'mysql' => [ + 'host' => 'localhost', + 'driver' => 'mysql', + 'username' => 'user', + 'password' => 'pass' + ], + 'sqlite' => [ + 'host' => 'vfs://root/database.sqlite', + 'driver' => 'sqlite', + 'username' => 'user', + 'password' => 'pass' + ] + ] + ]; + + $config = ConfigurationBuilder::create() + ->addFile('config.yml') + ->addDirectory($this->getRoot()->url()) + ->setConfigurationClass(ConfigurationConstructor::class) + ->setDefinition(new DatabaseConfiguration()) + ->setReplaces(['kernel_dir' => 'vfs://root']) + ->getConfigurationArray() + ; + + expect($config)->toBe($expected); +});