diff --git a/fixtures/Bridge/Symfony/Application/AppKernel.php b/fixtures/Bridge/Symfony/Application/AppKernel.php index 70d6d151a..49c409a49 100644 --- a/fixtures/Bridge/Symfony/Application/AppKernel.php +++ b/fixtures/Bridge/Symfony/Application/AppKernel.php @@ -19,7 +19,6 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\HttpKernel\Kernel; class AppKernel extends Kernel @@ -63,7 +62,7 @@ public function registerContainerConfiguration(LoaderInterface $loader) */ public function build(ContainerBuilder $container) { - $container->addCompilerPass(new class implements CompilerPassInterface { + $container->addCompilerPass(new class() implements CompilerPassInterface { public function process(ContainerBuilder $container) { foreach ($container->getDefinitions() as $id => $definition) { diff --git a/src/Bridge/Symfony/Resources/config/fixture_builder/expression_language/token_parser.xml b/src/Bridge/Symfony/Resources/config/fixture_builder/expression_language/token_parser.xml index 2022ec5b7..fecb56e9e 100644 --- a/src/Bridge/Symfony/Resources/config/fixture_builder/expression_language/token_parser.xml +++ b/src/Bridge/Symfony/Resources/config/fixture_builder/expression_language/token_parser.xml @@ -70,6 +70,11 @@ + + + + diff --git a/src/FixtureBuilder/ExpressionLanguage/Lexer/ReferenceLexer.php b/src/FixtureBuilder/ExpressionLanguage/Lexer/ReferenceLexer.php index 594b7c504..800527f8c 100644 --- a/src/FixtureBuilder/ExpressionLanguage/Lexer/ReferenceLexer.php +++ b/src/FixtureBuilder/ExpressionLanguage/Lexer/ReferenceLexer.php @@ -35,6 +35,7 @@ final class ReferenceLexer implements LexerInterface '/^@[^\ @]+\{.*,.*}/' => TokenType::LIST_REFERENCE_TYPE, '/^@.*\*/' => TokenType::WILDCARD_REFERENCE_TYPE, '/^@.*->.*/' => null, + '/^@\S+\$\S+/' => TokenType::VARIABLE_REFERENCE_TYPE, '/^@\S+/' => TokenType::SIMPLE_REFERENCE_TYPE, '/^@/' => TokenType::SIMPLE_REFERENCE_TYPE, ]; diff --git a/src/FixtureBuilder/ExpressionLanguage/Parser/FunctionFixtureReferenceParser.php b/src/FixtureBuilder/ExpressionLanguage/Parser/FunctionFixtureReferenceParser.php index 0da6ac616..7902ee6cf 100644 --- a/src/FixtureBuilder/ExpressionLanguage/Parser/FunctionFixtureReferenceParser.php +++ b/src/FixtureBuilder/ExpressionLanguage/Parser/FunctionFixtureReferenceParser.php @@ -53,7 +53,7 @@ public function parse(string $value) $mergedValues = array_reduce( $parsedValue->getValue(), [$this, 'mergeFunctionFixtureReferences'], - $initial = [] + [] ); return (1 === count($mergedValues)) diff --git a/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/SimpleReferenceTokenParser.php b/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/SimpleReferenceTokenParser.php index 36893e335..048c35d5f 100644 --- a/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/SimpleReferenceTokenParser.php +++ b/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/SimpleReferenceTokenParser.php @@ -13,6 +13,7 @@ namespace Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\TokenParser\Chainable; +use InvalidArgumentException; use Nelmio\Alice\Definition\Value\FixtureReferenceValue; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\ChainableTokenParserInterface; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Token; @@ -46,7 +47,7 @@ public function parse(Token $token): FixtureReferenceValue try { return new FixtureReferenceValue(substr($value, 1)); - } catch (\InvalidArgumentException $exception) { + } catch (InvalidArgumentException $exception) { throw ExpressionLanguageExceptionFactory::createForUnparsableToken($token, 0, $exception); } } diff --git a/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/VariableReferenceTokenParser.php b/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/VariableReferenceTokenParser.php new file mode 100644 index 000000000..026882ca3 --- /dev/null +++ b/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/VariableReferenceTokenParser.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\TokenParser\Chainable; + +use InvalidArgumentException; +use Nelmio\Alice\Definition\Value\FixtureReferenceValue; +use Nelmio\Alice\Definition\Value\FunctionCallValue; +use Nelmio\Alice\Definition\Value\ListValue; +use Nelmio\Alice\Definition\Value\ValueForCurrentValue; +use Nelmio\Alice\Definition\Value\VariableValue; +use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\ChainableTokenParserInterface; +use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Token; +use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\TokenType; +use Nelmio\Alice\IsAServiceTrait; +use Nelmio\Alice\Throwable\Exception\FixtureBuilder\ExpressionLanguage\ExpressionLanguageExceptionFactory; + +/** + * @internal + */ +final class VariableReferenceTokenParser implements ChainableTokenParserInterface +{ + use IsAServiceTrait; + + /** + * @inheritdoc + */ + public function canParse(Token $token): bool + { + return $token->getType() === TokenType::VARIABLE_REFERENCE_TYPE; + } + + /** + * Parses expressions such as "@user$foo". + * + * {@inheritdoc} + */ + public function parse(Token $token): FixtureReferenceValue + { + $parts = explode('$', $token->getValue()); + + $variable = $parts[1]; + + try { + return new FixtureReferenceValue( + new ListValue([ + substr($parts[0], 1), + 'current' === $variable + ? new FunctionCallValue( + 'current', + [new ValueForCurrentValue()] + ) + : new VariableValue($variable) + ]) + ); + } catch (InvalidArgumentException $exception) { + throw ExpressionLanguageExceptionFactory::createForUnparsableToken($token, 0, $exception); + } + } +} diff --git a/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/VariableTokenParser.php b/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/VariableTokenParser.php index 57d56c193..21a4f2a55 100644 --- a/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/VariableTokenParser.php +++ b/src/FixtureBuilder/ExpressionLanguage/Parser/TokenParser/Chainable/VariableTokenParser.php @@ -13,6 +13,8 @@ namespace Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\TokenParser\Chainable; +use Nelmio\Alice\Definition\Value\FunctionCallValue; +use Nelmio\Alice\Definition\Value\ValueForCurrentValue; use Nelmio\Alice\Definition\Value\VariableValue; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\ChainableTokenParserInterface; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Token; @@ -20,6 +22,7 @@ use Nelmio\Alice\IsAServiceTrait; use Nelmio\Alice\Throwable\Exception\FixtureBuilder\ExpressionLanguage\ExpressionLanguageExceptionFactory; use Nelmio\Alice\Throwable\Exception\FixtureBuilder\ExpressionLanguage\ParseException; +use TypeError; /** * @internal @@ -45,9 +48,18 @@ public function canParse(Token $token): bool */ public function parse(Token $token) { + $variable = substr($token->getValue(), 1); + + if ('current' === $variable) { + return new FunctionCallValue( + 'current', + [new ValueForCurrentValue()] + ); + } + try { - return new VariableValue(substr($token->getValue(), 1)); - } catch (\TypeError $error) { + return new VariableValue($variable); + } catch (TypeError $error) { throw ExpressionLanguageExceptionFactory::createForUnparsableToken($token, 0, $error); } } diff --git a/src/FixtureBuilder/ExpressionLanguage/TokenType.php b/src/FixtureBuilder/ExpressionLanguage/TokenType.php index b0863b761..c75a1d972 100644 --- a/src/FixtureBuilder/ExpressionLanguage/TokenType.php +++ b/src/FixtureBuilder/ExpressionLanguage/TokenType.php @@ -36,6 +36,7 @@ final class TokenType const RANGE_REFERENCE_TYPE = 'RANGE_REFERENCE_TYPE'; const PROPERTY_REFERENCE_TYPE = 'PROPERTY_REFERENCE_TYPE'; const METHOD_REFERENCE_TYPE = 'METHOD_REFERENCE_TYPE'; + const VARIABLE_REFERENCE_TYPE = 'VARIABLE_REFERENCE_TYPE'; const VARIABLE_TYPE = 'VARIABLE_TYPE'; @@ -54,6 +55,7 @@ final class TokenType self::RANGE_REFERENCE_TYPE => true, self::PROPERTY_REFERENCE_TYPE => true, self::METHOD_REFERENCE_TYPE => true, + self::VARIABLE_REFERENCE_TYPE => true, self::VARIABLE_TYPE => true, ]; diff --git a/src/Loader/NativeLoader.php b/src/Loader/NativeLoader.php index 0e7e41768..c098b2911 100644 --- a/src/Loader/NativeLoader.php +++ b/src/Loader/NativeLoader.php @@ -83,6 +83,7 @@ use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\TokenParser\Chainable\StringArrayTokenParser; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\TokenParser\Chainable\StringTokenParser; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\TokenParser\Chainable\TolerantFunctionTokenParser; +use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\TokenParser\Chainable\VariableReferenceTokenParser; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\TokenParser\Chainable\VariableTokenParser; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\TokenParser\Chainable\WildcardReferenceTokenParser; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Parser\TokenParser\TokenParserRegistry; @@ -468,6 +469,7 @@ protected function createExpressionLanguageTokenParser(): TokenParserInterface new OptionalTokenParser(), new ParameterTokenParser(), new PropertyReferenceTokenParser(), + new VariableReferenceTokenParser(), new SimpleReferenceTokenParser(), new StringArrayTokenParser(), new StringTokenParser($argumentEscaper), diff --git a/tests/FixtureBuilder/ExpressionLanguage/Lexer/LexerIntegrationTest.php b/tests/FixtureBuilder/ExpressionLanguage/Lexer/LexerIntegrationTest.php index f3df4ffab..5c0b87b6c 100644 --- a/tests/FixtureBuilder/ExpressionLanguage/Lexer/LexerIntegrationTest.php +++ b/tests/FixtureBuilder/ExpressionLanguage/Lexer/LexerIntegrationTest.php @@ -13,6 +13,7 @@ namespace Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Lexer; +use InvalidArgumentException; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\LexerInterface; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\Token; use Nelmio\Alice\FixtureBuilder\ExpressionLanguage\TokenType; @@ -56,7 +57,7 @@ public function testCanLexValues(string $value, $expected) ) ); } - } catch (\InvalidArgumentException $exception) { + } catch (InvalidArgumentException $exception) { if (null === $expected) { return; } @@ -841,6 +842,12 @@ public function provideValues() new Token('@user{1..2}->username', new TokenType(TokenType::PROPERTY_REFERENCE_TYPE)), ], ]; + yield '[Reference] variable with prop' => [ + '@user$current->username', + [ + new Token('@user$current->username', new TokenType(TokenType::PROPERTY_REFERENCE_TYPE)), + ], + ]; yield '[Reference] left with prop' => [ 'foo @user0->username', [ @@ -1022,6 +1029,12 @@ public function provideValues() new Token(' bar', new TokenType(TokenType::STRING_TYPE)), ], ]; + yield '[Reference] reference variable' => [ + '@user0$foo', + [ + new Token('@user0$foo', new TokenType(TokenType::VARIABLE_REFERENCE_TYPE)), + ], + ]; yield '[Reference] reference function' => [ '@user0', [ diff --git a/tests/FixtureBuilder/ExpressionLanguage/Parser/ParserIntegrationTest.php b/tests/FixtureBuilder/ExpressionLanguage/Parser/ParserIntegrationTest.php index 5c46643f5..005fef7ec 100644 --- a/tests/FixtureBuilder/ExpressionLanguage/Parser/ParserIntegrationTest.php +++ b/tests/FixtureBuilder/ExpressionLanguage/Parser/ParserIntegrationTest.php @@ -890,6 +890,18 @@ public function provideValues() 'username' ), ]; + yield '[Reference] variable with prop' => [ + '@user$foo->username', + new FixturePropertyValue( + new FixtureReferenceValue( + new ListValue([ + 'user', + new VariableValue('foo'), + ]) + ), + 'username' + ), + ]; yield '[Reference] left with prop' => [ 'foo @user0->username', new ListValue([ @@ -1099,6 +1111,15 @@ public function provideValues() ' bar', ]), ]; + yield '[Reference] reference variable' => [ + '@user0$foo', + new FixtureReferenceValue( + new ListValue([ + 'user0', + new VariableValue('foo') + ]) + ), + ]; yield '[Reference] reference function' => [ '@user0', new FixtureReferenceValue( diff --git a/tests/Loader/LoaderIntegrationTest.php b/tests/Loader/LoaderIntegrationTest.php index 55f9884c0..b9991d286 100644 --- a/tests/Loader/LoaderIntegrationTest.php +++ b/tests/Loader/LoaderIntegrationTest.php @@ -2025,6 +2025,36 @@ public function provideFixturesToGenerate() ], ]; + yield 'dynamic reference with variable' => [ + [ + stdClass::class => [ + 'dummy{1..2}' => [ + 'name' => '', + ], + 'another_dummy{1..2}' => [ + 'dummy' => '@dummy$current', + ], + ], + ], + [ + 'parameters' => [], + 'objects' => [ + 'dummy1' => $dummy1 = StdClassFactory::create([ + 'name' => '1', + ]), + 'dummy2' => $dummy2 = StdClassFactory::create([ + 'name' => '2', + ]), + 'another_dummy1' => StdClassFactory::create([ + 'dummy' => $dummy1, + ]), + 'another_dummy2' => StdClassFactory::create([ + 'dummy' => $dummy2, + ]), + ], + ], + ]; + yield 'property reference value' => [ [ stdClass::class => [ @@ -2073,6 +2103,36 @@ public function provideFixturesToGenerate() ], ]; + yield 'dynamic property reference value' => [ + [ + stdClass::class => [ + 'dummy{1..2}' => [ + 'name' => '', + ], + 'another_dummy{1..2}' => [ + 'dummy' => '@dummy$current->name', + ], + ], + ], + [ + 'parameters' => [], + 'objects' => [ + 'dummy1' => $dummy1 = StdClassFactory::create([ + 'name' => '1', + ]), + 'dummy2' => $dummy2 = StdClassFactory::create([ + 'name' => '2', + ]), + 'another_dummy1' => StdClassFactory::create([ + 'dummy' => '1', + ]), + 'another_dummy2' => StdClassFactory::create([ + 'dummy' => '2', + ]), + ], + ], + ]; + yield 'non existing property reference' => [ [ stdClass::class => [ @@ -2782,6 +2842,12 @@ public function provideFixturesToGenerate() 'dummy_{alice, bob}' => [ 'val' => '', ], + 'dummy_var{1..2}' => [ + 'val' => '$current', + ], + 'dummy_var_{alice, bob}' => [ + 'val' => '$current', + ], ], ], [ @@ -2799,6 +2865,18 @@ public function provideFixturesToGenerate() 'dummy_bob' => StdClassFactory::create([ 'val' => 'bob', ]), + 'dummy_var1' => StdClassFactory::create([ + 'val' => 1, + ]), + 'dummy_var2' => StdClassFactory::create([ + 'val' => 2, + ]), + 'dummy_var_alice' => StdClassFactory::create([ + 'val' => 'alice', + ]), + 'dummy_var_bob' => StdClassFactory::create([ + 'val' => 'bob', + ]), ], ], ];