From 28fc08ddefdbc9c186e633255f240aa063f28d44 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 1 Aug 2025 21:08:28 +0300 Subject: [PATCH 1/6] Add `AliasReference` --- CHANGELOG.md | 1 + composer.json | 6 ++-- psalm.xml | 1 + src/AliasReference.php | 36 +++++++++++++++++++++++ tests/AliasReferenceTest.php | 56 ++++++++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 src/AliasReference.php create mode 100644 tests/AliasReferenceTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index caa85fd..700ed9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Chg #83: Bump PHP minimal version to 8.1 (@vjik) - Chg #81, #83: Change PHP constraint in `composer.json` to `8.1 - 8.4` (@vjik) +- New #84: Add `AliasReference` (@vjik) ## 3.0.0 February 13, 2023 diff --git a/composer.json b/composer.json index e2808a6..80d5994 100644 --- a/composer.json +++ b/composer.json @@ -31,11 +31,14 @@ "require-dev": { "maglnet/composer-require-checker": "^4.7.1", "phpunit/phpunit": "^10.5.48", + "psr/container": "^2.0.2", "rector/rector": "^2.1.2", "roave/infection-static-analysis-plugin": "^1.35", "spatie/phpunit-watcher": "^1.24.0", "vimeo/psalm": "^5.26.1 || ^6.13", - "yiisoft/di": "^1.4" + "yiisoft/definitions": "^3.4", + "yiisoft/di": "^1.4", + "yiisoft/test-support": "^3.0.2" }, "autoload": { "psr-4": { @@ -49,7 +52,6 @@ }, "config": { "sort-packages": true, - "bump-after-update": "dev", "allow-plugins": { "infection/extension-installer": true, "composer/package-versions-deprecated": true diff --git a/psalm.xml b/psalm.xml index 9abd890..59deced 100644 --- a/psalm.xml +++ b/psalm.xml @@ -3,6 +3,7 @@ errorLevel="1" findUnusedBaselineEntry="true" findUnusedCode="false" + ensureOverrideAttribute="false" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" diff --git a/src/AliasReference.php b/src/AliasReference.php new file mode 100644 index 0000000..b22fc2d --- /dev/null +++ b/src/AliasReference.php @@ -0,0 +1,36 @@ +alias = $alias; + } + + public static function to(mixed $id): self + { + if (!is_string($id)) { + throw new InvalidArgumentException('Alias must be a string.'); + } + return new self($id); + } + + public function resolve(ContainerInterface $container): string + { + /** @var Aliases $aliases */ + $aliases = $container->get(Aliases::class); + return $aliases->get($this->alias); + } +} diff --git a/tests/AliasReferenceTest.php b/tests/AliasReferenceTest.php new file mode 100644 index 0000000..9447111 --- /dev/null +++ b/tests/AliasReferenceTest.php @@ -0,0 +1,56 @@ + new Aliases([ + '@app' => '/path/to/app', + '@runtime' => '@app/runtime' + ]), + ]); + + $reference = AliasReference::to($alias); + + assertSame($expected, $reference->resolve($container)); + } + + public static function dataInvalidValue(): array + { + return [ + 'int' => [123], + 'null' => [null], + 'array' => [['@app']], + 'object' => [new stdClass()], + 'float' => [12.3], + 'boolean' => [true], + ]; + } + + #[DataProvider('dataInvalidValue')] + public function testInvalidValue(mixed $value): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Alias must be a string.'); + AliasReference::to($value); + } +} From 8447bf502c60a70cccbe4c458992f801f682b940 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 1 Aug 2025 21:14:35 +0300 Subject: [PATCH 2/6] phpdoc --- src/AliasReference.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/AliasReference.php b/src/AliasReference.php index b22fc2d..450f2a5 100644 --- a/src/AliasReference.php +++ b/src/AliasReference.php @@ -10,15 +10,33 @@ use function is_string; +/** + * Reference to an alias that will be resolved at runtime. + */ final class AliasReference implements ReferenceInterface { + /** + * @var string The alias to be resolved. + */ private string $alias; + /** + * @param string $alias The alias to be resolved. + */ private function __construct(string $alias) { $this->alias = $alias; } + /** + * Creates a new alias reference. + * + * @param string $id The alias to be resolved. + * + * @return self An instance of reference. + * + * @psalm-suppress MoreSpecificImplementedParamType, DocblockTypeContradiction + */ public static function to(mixed $id): self { if (!is_string($id)) { @@ -27,6 +45,13 @@ public static function to(mixed $id): self return new self($id); } + /** + * Retrieves {@see Aliases} from the container and uses it to resolve the alias to its actual path. + * + * @param ContainerInterface $container The DI container. + * + * @return string The resolved path for the alias. + */ public function resolve(ContainerInterface $container): string { /** @var Aliases $aliases */ From 86e034fa0649041155d29ed2cabb9b13565aeef9 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 1 Aug 2025 21:17:51 +0300 Subject: [PATCH 3/6] docs --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 8454ec9..5505281 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,23 @@ $aliases = new Aliases([ $aliases->remove('@root'); ``` +### Alias references + +The package provides `AliasReference` class that implements `ReferenceInterface` from +[Yii Definition](https://github.com/yiisoft/definitions). It allows you to create references to aliases +that will be resolved at runtime: + +```php +// Create a reference to an alias +$reference = \Yiisoft\Aliases\AliasReference::to('@public/assets'); + +// The reference will be resolved when needed +$configPath = $reference->resolve($container); +``` + +This is particularly useful in dependency injection configurations where you want to inject resolved paths +but the aliases are not available at configuration time. + ## Documentation - [Internals](docs/internals.md) From d63c9f836a20a41b79e06af6496f4f63517ad4c0 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Fri, 1 Aug 2025 18:18:02 +0000 Subject: [PATCH 4/6] Apply fixes from StyleCI --- tests/AliasReferenceTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AliasReferenceTest.php b/tests/AliasReferenceTest.php index 9447111..6e1420d 100644 --- a/tests/AliasReferenceTest.php +++ b/tests/AliasReferenceTest.php @@ -25,7 +25,7 @@ public function testResolve(string $expected, string $alias): void $container = new SimpleContainer([ Aliases::class => new Aliases([ '@app' => '/path/to/app', - '@runtime' => '@app/runtime' + '@runtime' => '@app/runtime', ]), ]); From f1833931da88471117e1967aab14971225e28b90 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 1 Aug 2025 21:22:16 +0300 Subject: [PATCH 5/6] fix --- composer-require-checker.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 composer-require-checker.json diff --git a/composer-require-checker.json b/composer-require-checker.json new file mode 100644 index 0000000..5445642 --- /dev/null +++ b/composer-require-checker.json @@ -0,0 +1,18 @@ +{ + "symbol-whitelist": [ + "Psr\\Container\\ContainerInterface", + "Yiisoft\\Definitions\\Contract\\ReferenceInterface" + ], + "php-core-extensions": [ + "Core", + "date", + "json", + "pcre", + "Phar", + "Reflection", + "SPL", + "standard", + "fileinfo" + ], + "scan-files": [] +} From 91ed0f340056d7c7119585fe061c87a35c44e57d Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Fri, 1 Aug 2025 21:24:09 +0300 Subject: [PATCH 6/6] fix --- tests/AliasReferenceTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AliasReferenceTest.php b/tests/AliasReferenceTest.php index 6e1420d..c446cfc 100644 --- a/tests/AliasReferenceTest.php +++ b/tests/AliasReferenceTest.php @@ -18,7 +18,7 @@ final class AliasReferenceTest extends TestCase { #[TestWith(['/path/to/app', '@app'])] - #[TestWith(['/path/to/app/runtime/test', '@runtime/test'])] + #[TestWith(['/path/to/app/runtime/logs', '@runtime/logs'])] #[TestWith(['/test/path', '/test/path'])] public function testResolve(string $expected, string $alias): void {