diff --git a/.gitignore b/.gitignore index 5a685f78..f527b7c1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /my-app.* /var/ /vendor/ +.idea/ diff --git a/CHANGELOG.md b/CHANGELOG.md index c6649c7d..9129db86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Add a `yaml_dump()` function to dump any PHP value to a YAML string * Add a `yaml_parse()` function to parse a YAML string to a PHP value * Remove the default timeout of 60 seconds from the Context +* Add possibility to use [Property Access Component](https://symfony.com/doc/current/components/property_access.html) syntax for getting variable from context. ## 0.13.1 (2024-02-27) diff --git a/composer.json b/composer.json index 9196fa27..943b7942 100644 --- a/composer.json +++ b/composer.json @@ -43,6 +43,7 @@ "symfony/http-client": "^6.4.3", "symfony/monolog-bridge": "^6.4.3", "symfony/process": "^6.4.3", + "symfony/property-access": "^6.4", "symfony/string": "^6.4.3", "symfony/translation-contracts": "^3.4.1", "symfony/var-dumper": "^6.4.3", diff --git a/composer.lock b/composer.lock index 612ecc71..d23b0612 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "16e5f7934a962f8c5ad979ca1c6cc176", + "content-hash": "a08187a40ca9c74303089d9e6d917d6b", "packages": [ { "name": "jolicode/jolinotif", @@ -2342,6 +2342,166 @@ ], "time": "2024-01-23T14:51:35+00:00" }, + { + "name": "symfony/property-access", + "version": "v6.4.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "c0664db266024013e31446dd690b6bfcf218ad93" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/c0664db266024013e31446dd690b6bfcf218ad93", + "reference": "c0664db266024013e31446dd690b6bfcf218ad93", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/property-info": "^5.4|^6.0|^7.0" + }, + "require-dev": { + "symfony/cache": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property-path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v6.4.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-02-16T13:31:43+00:00" + }, + { + "name": "symfony/property-info", + "version": "v6.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "e96d740ab5ac39aa530c8eaa0720ea8169118e26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/e96d740ab5ac39aa530c8eaa0720ea8169118e26", + "reference": "e96d740ab5ac39aa530c8eaa0720ea8169118e26", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/string": "^5.4|^6.0|^7.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/dependency-injection": "<5.4", + "symfony/serializer": "<6.4" + }, + "require-dev": { + "phpdocumentor/reflection-docblock": "^5.2", + "phpstan/phpdoc-parser": "^1.0", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts information about PHP class' properties using metadata of popular sources", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "support": { + "source": "https://github.com/symfony/property-info/tree/v6.4.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-23T14:51:35+00:00" + }, { "name": "symfony/service-contracts", "version": "v3.4.1", @@ -3448,5 +3608,5 @@ "platform-overrides": { "php": "8.1.19" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.2.0" } diff --git a/doc/getting-started/context.md b/doc/getting-started/context.md index 687e003d..2b4f2e95 100644 --- a/doc/getting-started/context.md +++ b/doc/getting-started/context.md @@ -53,13 +53,15 @@ function foo(): void { $foobar = variable('foobar', 'default value'); - // Same as: $context = context(); - try { - $foobar = $context['foobar']; - } catch (\OutOfBoundsException) { - $foobar = 'default value; - } + // Same as: + $foobar = $context['foobar'] ?? 'default value'; + + // Getting nested values + $foobar = variable('[foo][bar][baz]', 'default value'); + + // Same as: + $foobar = $context['foo']['bar']['baz'] ?? 'default value'; } ``` diff --git a/examples/context.php b/examples/context.php index 27154bc0..8a7e3c48 100644 --- a/examples/context.php +++ b/examples/context.php @@ -21,6 +21,9 @@ function defaultContext(): Context 'name' => 'my_default', 'production' => false, 'foo' => 'bar', + 'nested' => [ + 'key' => 'nested_value', + ], ]); } @@ -83,6 +86,7 @@ function contextInfo(): void echo 'Production? ' . (variable('production', false) ? 'yes' : 'no') . "\n"; echo "verbosity: {$context->verbosityLevel->value}\n"; echo 'context: ' . variable('foo', 'N/A') . "\n"; + echo 'nested key: ' . variable('[nested][key]', 'N/A') . "\n"; } /** diff --git a/src/Attribute/AsCommandArgument.php b/src/Attribute/AsCommandArgument.php index e1ea8963..180f7ae2 100644 --- a/src/Attribute/AsCommandArgument.php +++ b/src/Attribute/AsCommandArgument.php @@ -5,7 +5,7 @@ abstract class AsCommandArgument { public function __construct( - public readonly string|null $name = null, + public readonly ?string $name = null, ) { } } diff --git a/src/Attribute/AsOption.php b/src/Attribute/AsOption.php index 870e1e68..fa93cfa4 100644 --- a/src/Attribute/AsOption.php +++ b/src/Attribute/AsOption.php @@ -12,7 +12,7 @@ class AsOption extends AsCommandArgument public function __construct( ?string $name = null, public readonly string|array|null $shortcut = null, - public readonly int|null $mode = null, + public readonly ?int $mode = null, public readonly string $description = '', public readonly array $suggestedValues = [], ) { diff --git a/src/Attribute/AsTask.php b/src/Attribute/AsTask.php index 391bcae1..e681d0a1 100644 --- a/src/Attribute/AsTask.php +++ b/src/Attribute/AsTask.php @@ -11,7 +11,7 @@ class AsTask */ public function __construct( public string $name = '', - public string|null $namespace = null, + public ?string $namespace = null, public string $description = '', public array $aliases = [], public array $onSignals = [], diff --git a/src/Context.php b/src/Context.php index c34fbd12..a1b4c837 100644 --- a/src/Context.php +++ b/src/Context.php @@ -17,7 +17,7 @@ public function __construct( ?string $currentDirectory = null, public readonly bool $tty = false, public readonly bool $pty = true, - public readonly float|null $timeout = null, + public readonly ?float $timeout = null, public readonly bool $quiet = false, public readonly bool $allowFailure = false, public readonly bool $notify = false, @@ -132,7 +132,7 @@ public function withPty(bool $pty = true): self ); } - public function withTimeout(float|null $timeout): self + public function withTimeout(?float $timeout): self { return new self( $this->data, diff --git a/src/ContextRegistry.php b/src/ContextRegistry.php index faa79ca7..cd75f097 100644 --- a/src/ContextRegistry.php +++ b/src/ContextRegistry.php @@ -2,6 +2,8 @@ namespace Castor; +use Symfony\Component\PropertyAccess\PropertyAccess; + /** @internal */ class ContextRegistry { @@ -113,11 +115,11 @@ public function getVariable(string $key, mixed $default = null): mixed { $context = $this->getCurrentContext(); - if (!isset($context[$key])) { - return $default; + if (str_starts_with($key, '[')) { + return PropertyAccess::createPropertyAccessor()->getValue($context, $key) ?? $default; } - return $context[$key]; + return $context[$key] ?? $default; } /** diff --git a/src/SectionOutput.php b/src/SectionOutput.php index b3c0a24e..3a37a6a0 100644 --- a/src/SectionOutput.php +++ b/src/SectionOutput.php @@ -14,7 +14,7 @@ class SectionOutput private OutputInterface|ConsoleSectionOutput $consoleOutput; - private ConsoleOutput|null $mainOutput; + private ?ConsoleOutput $mainOutput; /** @var \SplObjectStorage */ private \SplObjectStorage $sections; diff --git a/tests/Examples/Generated/ContextContextDynamicTest.php.output.txt b/tests/Examples/Generated/ContextContextDynamicTest.php.output.txt index b5e52a95..9d8204e0 100644 --- a/tests/Examples/Generated/ContextContextDynamicTest.php.output.txt +++ b/tests/Examples/Generated/ContextContextDynamicTest.php.output.txt @@ -2,3 +2,4 @@ context name: dynamic Production? no verbosity: 1 context: baz +nested key: N/A diff --git a/tests/Examples/Generated/ContextContextMyDefaultTest.php.output.txt b/tests/Examples/Generated/ContextContextMyDefaultTest.php.output.txt index d9f99d5a..18ee1071 100644 --- a/tests/Examples/Generated/ContextContextMyDefaultTest.php.output.txt +++ b/tests/Examples/Generated/ContextContextMyDefaultTest.php.output.txt @@ -2,3 +2,4 @@ context name: my_default Production? no verbosity: 2 context: bar +nested key: nested_value diff --git a/tests/Examples/Generated/ContextContextPathTest.php.output.txt b/tests/Examples/Generated/ContextContextPathTest.php.output.txt index bf1dfcde..94c61039 100644 --- a/tests/Examples/Generated/ContextContextPathTest.php.output.txt +++ b/tests/Examples/Generated/ContextContextPathTest.php.output.txt @@ -2,3 +2,4 @@ context name: path Production? yes verbosity: 1 context: bar +nested key: N/A diff --git a/tests/Examples/Generated/ContextContextProductionTest.php.output.txt b/tests/Examples/Generated/ContextContextProductionTest.php.output.txt index e30eb5ba..15c9bbd9 100644 --- a/tests/Examples/Generated/ContextContextProductionTest.php.output.txt +++ b/tests/Examples/Generated/ContextContextProductionTest.php.output.txt @@ -2,3 +2,4 @@ context name: production Production? yes verbosity: 1 context: bar +nested key: nested_value diff --git a/tests/Examples/Generated/ContextContextRunTest.php.output.txt b/tests/Examples/Generated/ContextContextRunTest.php.output.txt index b371862f..91a81c7b 100644 --- a/tests/Examples/Generated/ContextContextRunTest.php.output.txt +++ b/tests/Examples/Generated/ContextContextRunTest.php.output.txt @@ -2,3 +2,4 @@ context name: run Production? no verbosity: 1 context: no defined +nested key: N/A diff --git a/tests/Examples/Generated/ContextContextTest.php.output.txt b/tests/Examples/Generated/ContextContextTest.php.output.txt index 0d2e5e60..96dd0762 100644 --- a/tests/Examples/Generated/ContextContextTest.php.output.txt +++ b/tests/Examples/Generated/ContextContextTest.php.output.txt @@ -2,3 +2,4 @@ context name: my_default Production? no verbosity: 1 context: bar +nested key: nested_value diff --git a/tests/Examples/Generated/ContextContextWithTest.php.output.txt b/tests/Examples/Generated/ContextContextWithTest.php.output.txt index 280f111d..88408218 100644 --- a/tests/Examples/Generated/ContextContextWithTest.php.output.txt +++ b/tests/Examples/Generated/ContextContextWithTest.php.output.txt @@ -2,4 +2,5 @@ context name: dynamic Production? no verbosity: -1 context: bar -bar \ No newline at end of file +nested key: N/A +bar diff --git a/tools/php-cs-fixer/composer.lock b/tools/php-cs-fixer/composer.lock index 811d41a9..25a79a70 100644 --- a/tools/php-cs-fixer/composer.lock +++ b/tools/php-cs-fixer/composer.lock @@ -226,16 +226,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.49.0", + "version": "v3.51.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "8742f7aa6f72a399688b65e4f58992c2d4681fc2" + "reference": "127fa74f010da99053e3f5b62672615b72dd6efd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/8742f7aa6f72a399688b65e4f58992c2d4681fc2", - "reference": "8742f7aa6f72a399688b65e4f58992c2d4681fc2", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/127fa74f010da99053e3f5b62672615b72dd6efd", + "reference": "127fa74f010da99053e3f5b62672615b72dd6efd", "shasum": "" }, "require": { @@ -245,7 +245,7 @@ "ext-json": "*", "ext-tokenizer": "*", "php": "^7.4 || ^8.0", - "sebastian/diff": "^4.0 || ^5.0", + "sebastian/diff": "^4.0 || ^5.0 || ^6.0", "symfony/console": "^5.4 || ^6.0 || ^7.0", "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0", "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", @@ -266,7 +266,8 @@ "php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.4", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.4", - "phpunit/phpunit": "^9.6 || ^10.5.5", + "phpunit/phpunit": "^9.6 || ^10.5.5 || ^11.0.2", + "symfony/var-dumper": "^5.4 || ^6.0 || ^7.0", "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, "suggest": { @@ -305,7 +306,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.49.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.51.0" }, "funding": [ { @@ -313,7 +314,7 @@ "type": "github" } ], - "time": "2024-02-02T00:41:40+00:00" + "time": "2024-02-28T19:50:06+00:00" }, { "name": "psr/container", @@ -1819,5 +1820,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.2.0" }