├── .laminas-ci.json ├── COPYRIGHT.md ├── LICENSE.md ├── README.md ├── composer.json └── src ├── LazyParameterPostProcessor.php ├── ParameterNotFoundException.php └── ParameterPostProcessor.php /.laminas-ci.json: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /COPYRIGHT.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/) 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | - Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | - Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | - Neither the name of Laminas Foundation nor the names of its contributors may 14 | be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laminas-config-aggregator-parameters 2 | 3 | [![Build Status](https://github.com/laminas/laminas-config-aggregator-parameters/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/laminas/laminas-config-aggregator-parameters/actions/workflows/continuous-integration.yml) 4 | [![type-coverage](https://shepherd.dev/github/laminas/laminas-config-aggregator-parameters/coverage.svg)](https://shepherd.dev/github/laminas/laminas-config-aggregator-parameters) 5 | [![Psalm level](https://shepherd.dev/github/laminas/laminas-config-aggregator-parameters/level.svg)](https://shepherd.dev/github/laminas/laminas-config-aggregator-parameters) 6 | 7 | > ## 🇷🇺 Русским гражданам 8 | > 9 | > Мы, участники Laminas, родились и живем в разных странах. У многих из нас есть друзья, родственники и коллеги как в России, так и в Украине. Некоторые из нас родились в России. Некоторые из нас живут в России. У некоторых бабушки и дедушки сражались с фашистами во Второй мировой войне. Здесь никто не поддерживает фашизм. 10 | > 11 | > У одного из нас есть украинская родственница, которая спаслась из дома вместе с сыном. Поезд задержался из-за бомбежки на дороге впереди. У нас есть друзья, которые прячутся в бомбоубежищах. Мы с тревогой ждем весточки от них после воздушных налетов, которые беспорядочно наносят удары и попадают по больницам, школам, детским садам и домам. Мы не берем это из каких-либо СМИ. Мы наблюдаем это напрямую. 12 | > 13 | > Вы доверяете нам достаточно, чтоб использовать наши программы, и мы просим вас довериться нам вновь. Мы нуждаемся в помощи. Выходите и протестуйте против этой бесполезной войны. Остановите кровопролитие. Скажите "Нет войне!" 14 | > 15 | > ## 🇺🇸 To Citizens of Russia 16 | > 17 | > We at Laminas come from all over the world. Many of us have friends, family and colleagues in both Russia and Ukraine. Some of us were born in Russia. Some of us currently live in Russia. Some have grandparents who fought Nazis in World War II. Nobody here supports fascism. 18 | > 19 | > One team member has a Ukrainian relative who fled her home with her son. The train was delayed due to bombing on the road ahead. We have friends who are hiding in bomb shelters. We anxiously follow up on them after the air raids, which indiscriminately fire at hospitals, schools, kindergartens and houses. We're not taking this from any media. These are our actual experiences. 20 | > 21 | > You trust us enough to use our software. We ask that you trust us to say the truth on this. We need your help. Go out and protest this unnecessary war. Stop the bloodshed. Say "stop the war!" 22 | 23 | Provides an extension to the `laminas/laminas-config-aggregator` to allow parameters within your configuration. 24 | 25 | ## Installation 26 | 27 | Run the following to install this library: 28 | 29 | ```bash 30 | $ composer require laminas/laminas-config-aggregator-parameters 31 | ``` 32 | 33 | ## Usage 34 | 35 | ```php 36 | use Laminas\ConfigAggregator\ArrayProvider; 37 | use Laminas\ConfigAggregator\ConfigAggregator; 38 | use Laminas\ConfigAggregatorParameters\ParameterPostProcessor; 39 | 40 | $aggregator = new ConfigAggregator( 41 | [ 42 | new ArrayProvider([ 43 | 'parameter_usage' => '%foo%', 44 | 'parameter_name' => '%%foo%%', 45 | 'recursive_parameter_usage' => '%bar.baz%', 46 | 'parameterized_parameter_usage' => '%bar.quux%', 47 | ]), 48 | ], 49 | null, 50 | [ 51 | new ParameterPostProcessor([ 52 | 'foo' => 'bar', 53 | 'bar' => [ 54 | 'baz' => 'qoo', 55 | 'quux' => '%foo%', 56 | ], 57 | ]), 58 | ] 59 | ); 60 | 61 | var_dump($aggregator->getMergedConfig()); 62 | ``` 63 | 64 | Result: 65 | 66 | ```php 67 | array(5) { 68 | 'parameter_usage' => 69 | string(3) "bar" 70 | 'parameter_name' => 71 | string(5) "%foo%" 72 | 'recursive_parameter_usage' => 73 | string(3) "qoo" 74 | 'parameterized_parameter_usage' => 75 | string(3) "bar" 76 | 'parameters' => 77 | array(4) { 78 | 'foo' => 79 | string(3) "bar" 80 | 'bar' => 81 | array(2) { 82 | 'baz' => 83 | string(3) "qoo" 84 | 'quux' => 85 | string(3) "bar" 86 | } 87 | 'bar.baz' => 88 | string(3) "qoo" 89 | 'bar.quux' => 90 | string(3) "bar" 91 | } 92 | } 93 | ``` 94 | 95 | ## Documentation 96 | 97 | Browse the documentation online at [https://docs.laminas.dev/laminas-config-aggregator-parameters](https://docs.laminas.dev/laminas-config-aggregator-parameters). 98 | 99 | ## Support 100 | 101 | - Issues: [https://github.com/laminas/laminas-config-aggregator-parameters/issues](https://github.com/laminas/laminas-config-aggregator-parameters/issues) 102 | - Chat: [https://laminas.dev/chat](https://laminas.dev/chat) 103 | - Forum: [https://discourse.laminas.dev](https://discourse.laminas.dev) 104 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laminas/laminas-config-aggregator-parameters", 3 | "description": "PostProcessor extension for laminas/laminas-config-aggregator to allow usage of templated parameters within your configuration", 4 | "license": "BSD-3-Clause", 5 | "homepage": "https://laminas.dev", 6 | "support": { 7 | "docs": "https://docs.laminas.dev/laminas-config-aggregator-parameters/", 8 | "issues": "https://github.com/laminas/laminas-config-aggregator-parameters/issues", 9 | "source": "https://github.com/laminas/laminas-config-aggregator-parameters", 10 | "rss": "https://github.com/laminas/laminas-config-aggregator-parameters/releases.atom", 11 | "chat": "https://laminas.dev/chat", 12 | "forum": "https://discourse.laminas.dev" 13 | }, 14 | "config": { 15 | "sort-packages": true, 16 | "platform": { 17 | "php": "8.1.99" 18 | }, 19 | "allow-plugins": { 20 | "dealerdirect/phpcodesniffer-composer-installer": true 21 | } 22 | }, 23 | "extra": { 24 | }, 25 | "require": { 26 | "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", 27 | "laminas/laminas-config-aggregator": "^1.13", 28 | "laminas/laminas-stdlib": "^3.17", 29 | "symfony/dependency-injection": "^6.2.8 || ^7.0" 30 | }, 31 | "require-dev": { 32 | "laminas/laminas-coding-standard": "^3.1", 33 | "laminas/laminas-config": "^3.10.1", 34 | "phpunit/phpunit": "^10.5.46", 35 | "psalm/plugin-phpunit": "^0.19.5", 36 | "vimeo/psalm": "^6.12" 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "Laminas\\ConfigAggregatorParameters\\": "src/" 41 | } 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "LaminasTest\\ConfigAggregatorParameters\\": "test/" 46 | } 47 | }, 48 | "scripts": { 49 | "check": [ 50 | "@cs-check", 51 | "@test" 52 | ], 53 | "cs-check": "phpcs", 54 | "cs-fix": "phpcbf", 55 | "static-analysis": "psalm --shepherd --stats", 56 | "test": "phpunit --colors=always", 57 | "test-coverage": "phpunit --colors=always --coverage-clover clover.xml" 58 | }, 59 | "conflict": { 60 | "zendframework/zend-config-aggregator-parameters": "*" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/LazyParameterPostProcessor.php: -------------------------------------------------------------------------------- 1 | 9 | * @psalm-import-type ProcessedConfig from ParameterPostProcessor 10 | */ 11 | final class LazyParameterPostProcessor 12 | { 13 | /** 14 | * @var callable():array 15 | * @psalm-var callable():TParameters 16 | */ 17 | private $parameterProvider; 18 | 19 | /** 20 | * @param callable():array $parameterProvider 21 | * @psalm-param callable():TParameters $parameterProvider 22 | */ 23 | public function __construct(callable $parameterProvider) 24 | { 25 | $this->parameterProvider = $parameterProvider; 26 | } 27 | 28 | /** 29 | * @param array $config 30 | * @return array 31 | * @psalm-return ProcessedConfig 32 | */ 33 | public function __invoke(array $config): array 34 | { 35 | $parameterProvider = $this->parameterProvider; 36 | 37 | return (new ParameterPostProcessor($parameterProvider()))($config); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/ParameterNotFoundException.php: -------------------------------------------------------------------------------- 1 | getKey(); 30 | return new self(sprintf( 31 | 'Found key "%s" within configuration, but it has no associated parameter defined', 32 | $key 33 | ), $e->getCode(), $e, $key); 34 | } 35 | 36 | public function getKey(): string 37 | { 38 | return $this->key; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/ParameterPostProcessor.php: -------------------------------------------------------------------------------- 1 | 16 | * @psalm-type ProcessedConfig=array&array{parameters:array} 17 | * @final 18 | */ 19 | class ParameterPostProcessor 20 | { 21 | /** 22 | * @param array $parameters 23 | * @psalm-param TParameters $parameters 24 | */ 25 | public function __construct( 26 | private readonly array $parameters 27 | ) { 28 | } 29 | 30 | /** 31 | * @template TConfig of array 32 | * @param array $config 33 | * @return array 34 | * @psalm-return ProcessedConfig 35 | */ 36 | public function __invoke(array $config): array 37 | { 38 | try { 39 | $parameters = $this->getResolvedParameters(); 40 | 41 | array_walk_recursive($config, static function (mixed &$value) use ($parameters): void { 42 | /** @psalm-suppress MixedAssignment, MixedArgument */ 43 | $value = $parameters->unescapeValue($parameters->resolveValue($value)); 44 | }); 45 | } catch (SymfonyParameterNotFoundException $exception) { 46 | throw ParameterNotFoundException::fromException($exception); 47 | } 48 | 49 | /** @var array $allParameters */ 50 | $allParameters = $parameters->all(); 51 | $config['parameters'] = $allParameters; 52 | 53 | /** @psalm-var ProcessedConfig $config */ 54 | return $config; 55 | } 56 | 57 | private function resolveNestedParameters(array $values, string $prefix = ''): array 58 | { 59 | $convertedValues = []; 60 | /** @psalm-suppress MixedAssignment */ 61 | foreach ($values as $key => $value) { 62 | // Do not provide numeric keys as single parameter 63 | if (is_numeric($key)) { 64 | continue; 65 | } 66 | 67 | /** @psalm-suppress MixedAssignment */ 68 | $convertedValues[$prefix . $key] = $value; 69 | if (is_array($value)) { 70 | $convertedValues += $this->resolveNestedParameters($value, $prefix . $key . '.'); 71 | } 72 | } 73 | 74 | return $convertedValues; 75 | } 76 | 77 | private function getResolvedParameters(): ParameterBag 78 | { 79 | $resolved = $this->resolveNestedParameters($this->parameters); 80 | $bag = new ParameterBag($resolved); 81 | 82 | $bag->resolve(); 83 | return $bag; 84 | } 85 | } 86 | --------------------------------------------------------------------------------