diff --git a/src/Metadata/ApiResource.php b/src/Metadata/ApiResource.php index f5312c44994..4e24962ce8c 100644 --- a/src/Metadata/ApiResource.php +++ b/src/Metadata/ApiResource.php @@ -19,6 +19,7 @@ * Resource metadata attribute. * * @author Antoine Bluchet + * * @experimental */ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)] diff --git a/src/Metadata/Resource/Factory/AlternateUriResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/AlternateUriResourceMetadataCollectionFactory.php index b4a53581616..63889b37627 100644 --- a/src/Metadata/Resource/Factory/AlternateUriResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/AlternateUriResourceMetadataCollectionFactory.php @@ -17,6 +17,7 @@ /** * @author Antoine Bluchet + * * @experimental */ final class AlternateUriResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactory.php index 743e28b27d8..77f297871ff 100644 --- a/src/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactory.php @@ -41,6 +41,7 @@ * Creates a resource metadata from {@see ApiResource} annotations. * * @author Antoine Bluchet + * * @experimental */ final class AttributesResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/Factory/ExtractorResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/ExtractorResourceMetadataCollectionFactory.php index e2b2b02b041..aef5c8b9dd3 100644 --- a/src/Metadata/Resource/Factory/ExtractorResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/ExtractorResourceMetadataCollectionFactory.php @@ -31,6 +31,7 @@ * Creates a resource metadata from {@see Resource} extractors (XML, YAML). * * @author Vincent Chalamon + * * @experimental */ final class ExtractorResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/Factory/FiltersResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/FiltersResourceMetadataCollectionFactory.php index c04f8b4bae7..40480dfd558 100644 --- a/src/Metadata/Resource/Factory/FiltersResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/FiltersResourceMetadataCollectionFactory.php @@ -21,6 +21,7 @@ * Creates a resource metadata from {@see Resource} annotations. * * @author Antoine Bluchet + * * @experimental */ final class FiltersResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/Factory/FormatsResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/FormatsResourceMetadataCollectionFactory.php index e47a59631ee..dc7ae80f00d 100644 --- a/src/Metadata/Resource/Factory/FormatsResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/FormatsResourceMetadataCollectionFactory.php @@ -30,6 +30,7 @@ * * operation input/output formats * * @author Kévin Dunglas + * * @experimental */ final class FormatsResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/Factory/InputOutputResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/InputOutputResourceMetadataCollectionFactory.php index 30642449e87..b7ef90cc95b 100644 --- a/src/Metadata/Resource/Factory/InputOutputResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/InputOutputResourceMetadataCollectionFactory.php @@ -22,6 +22,7 @@ * Transforms the given input/output metadata to a normalized one. * * @author Antoine Bluchet + * * @experimental */ final class InputOutputResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/Factory/NotExposedOperationResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/NotExposedOperationResourceMetadataCollectionFactory.php index 621c82afae9..69f920901c0 100644 --- a/src/Metadata/Resource/Factory/NotExposedOperationResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/NotExposedOperationResourceMetadataCollectionFactory.php @@ -27,6 +27,7 @@ * This operation helps to generate resource IRI for items. * * @author Vincent Chalamon + * * @experimental */ final class NotExposedOperationResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/Factory/OperationNameResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/OperationNameResourceMetadataCollectionFactory.php index f83feedd331..f340888af3a 100644 --- a/src/Metadata/Resource/Factory/OperationNameResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/OperationNameResourceMetadataCollectionFactory.php @@ -21,6 +21,7 @@ * Creates a resource metadata from {@see Resource} annotations. * * @author Antoine Bluchet + * * @experimental */ final class OperationNameResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/Factory/PhpDocResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/PhpDocResourceMetadataCollectionFactory.php index 5798d58a04a..e50cf16c0bf 100644 --- a/src/Metadata/Resource/Factory/PhpDocResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/PhpDocResourceMetadataCollectionFactory.php @@ -23,6 +23,7 @@ * Extracts descriptions from PHPDoc. * * @author Kévin Dunglas + * * @experimental */ final class PhpDocResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/Factory/ResourceMetadataCollectionFactoryInterface.php b/src/Metadata/Resource/Factory/ResourceMetadataCollectionFactoryInterface.php index 710c3acfaef..44b0233254b 100644 --- a/src/Metadata/Resource/Factory/ResourceMetadataCollectionFactoryInterface.php +++ b/src/Metadata/Resource/Factory/ResourceMetadataCollectionFactoryInterface.php @@ -20,6 +20,7 @@ * Creates a resource metadata value object. * * @author Antoine Bluchet + * * @experimental */ interface ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/Factory/UriTemplateResourceMetadataCollectionFactory.php b/src/Metadata/Resource/Factory/UriTemplateResourceMetadataCollectionFactory.php index 28aaede40c7..25470ea5d84 100644 --- a/src/Metadata/Resource/Factory/UriTemplateResourceMetadataCollectionFactory.php +++ b/src/Metadata/Resource/Factory/UriTemplateResourceMetadataCollectionFactory.php @@ -24,6 +24,7 @@ /** * @author Antoine Bluchet + * * @experimental */ final class UriTemplateResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface diff --git a/src/Metadata/Resource/ResourceMetadataCollection.php b/src/Metadata/Resource/ResourceMetadataCollection.php index 22a2724a3ba..dff15ee6bb7 100644 --- a/src/Metadata/Resource/ResourceMetadataCollection.php +++ b/src/Metadata/Resource/ResourceMetadataCollection.php @@ -21,6 +21,7 @@ /** * @experimental + * * @extends \ArrayObject */ final class ResourceMetadataCollection extends \ArrayObject diff --git a/src/Serializer/JsonEncoder.php b/src/Serializer/JsonEncoder.php index d0325197a46..4b1be321528 100644 --- a/src/Serializer/JsonEncoder.php +++ b/src/Serializer/JsonEncoder.php @@ -35,7 +35,7 @@ public function __construct(private readonly string $format, private ?BaseJsonEn $this->jsonEncoder = new BaseJsonEncoder( // Encode <, >, ', &, and " characters in the JSON, making it also safe to be embedded into HTML. - new JsonEncode(['json_encode_options' => \JSON_HEX_TAG | \JSON_HEX_APOS | \JSON_HEX_AMP | \JSON_HEX_QUOT | \JSON_UNESCAPED_UNICODE]), + new JsonEncode(['json_encode_options' => \JSON_HEX_TAG | \JSON_HEX_APOS | \JSON_HEX_AMP | \JSON_HEX_QUOT | \JSON_UNESCAPED_UNICODE | \JSON_INVALID_UTF8_IGNORE]), new JsonDecode(['json_decode_associative' => true]) ); } diff --git a/src/State/ProcessorInterface.php b/src/State/ProcessorInterface.php index 71ee7edbcc2..4ef65d4a940 100644 --- a/src/State/ProcessorInterface.php +++ b/src/State/ProcessorInterface.php @@ -19,6 +19,7 @@ * Process data: send an email, persist to storage, add to queue etc. * * @author Antoine Bluchet + * * @experimental */ interface ProcessorInterface diff --git a/src/State/ProviderInterface.php b/src/State/ProviderInterface.php index 8aa1a9fc785..03dfaaf9fd8 100644 --- a/src/State/ProviderInterface.php +++ b/src/State/ProviderInterface.php @@ -19,6 +19,7 @@ * Retrieves data from a persistence layer. * * @author Antoine Bluchet + * * @experimental * * @template T of object diff --git a/src/Symfony/Security/ResourceAccessChecker.php b/src/Symfony/Security/ResourceAccessChecker.php index 6fe34496855..2f55b3a31e5 100644 --- a/src/Symfony/Security/ResourceAccessChecker.php +++ b/src/Symfony/Security/ResourceAccessChecker.php @@ -37,9 +37,7 @@ public function isGranted(string $resourceClass, string $expression, array $extr if (null === $this->tokenStorage || null === $this->authenticationTrustResolver) { throw new \LogicException('The "symfony/security" library must be installed to use the "security" attribute.'); } - if (null === $token = $this->tokenStorage->getToken()) { - $token = new NullToken(); - } + if (null === $this->expressionLanguage) { throw new \LogicException('The "symfony/expression-language" library must be installed to use the "security" attribute.'); } @@ -49,10 +47,12 @@ public function isGranted(string $resourceClass, string $expression, array $extr 'auth_checker' => $this->authorizationChecker, // needed for the is_granted expression function ]); - if ($token) { - $variables = array_merge($variables, $this->getVariables($token)); + if (null === $token = $this->tokenStorage->getToken()) { + $token = new NullToken(); } + $variables = array_merge($variables, $this->getVariables($token)); + return (bool) $this->expressionLanguage->evaluate($expression, $variables); } diff --git a/tests/Fixtures/DummyIgnoreProperty.php b/tests/Fixtures/DummyIgnoreProperty.php index 560738e6306..b5d6b81b0ea 100644 --- a/tests/Fixtures/DummyIgnoreProperty.php +++ b/tests/Fixtures/DummyIgnoreProperty.php @@ -27,6 +27,7 @@ class DummyIgnoreProperty /** * @Groups({"dummy"}) + * * @Ignore */ public $ignored; diff --git a/tests/Serializer/JsonEncoderTest.php b/tests/Serializer/JsonEncoderTest.php index 709cf6e5e24..b47d59f8198 100644 --- a/tests/Serializer/JsonEncoderTest.php +++ b/tests/Serializer/JsonEncoderTest.php @@ -51,4 +51,18 @@ public function testDecode(): void { $this->assertEquals(['foo' => 'bar'], $this->encoder->decode('{"foo":"bar"}', 'json')); } + + public function testUTF8EncodedString(): void + { + $data = ['foo' => 'Über']; + + $this->assertEquals('{"foo":"Über"}', $this->encoder->encode($data, 'json')); + } + + public function testUTF8MalformedHandlingEncoding(): void + { + $data = ['foo' => pack('H*', 'B11111')]; + + $this->assertEquals('{"foo":"\u0011\u0011"}', $this->encoder->encode($data, 'json')); + } } diff --git a/tests/Symfony/Bundle/DataCollector/RequestDataCollectorTest.php b/tests/Symfony/Bundle/DataCollector/RequestDataCollectorTest.php index 9eafe136080..9a0fb828f8f 100644 --- a/tests/Symfony/Bundle/DataCollector/RequestDataCollectorTest.php +++ b/tests/Symfony/Bundle/DataCollector/RequestDataCollectorTest.php @@ -205,7 +205,7 @@ private function apiResourceClassWillReturn(?string $data, array $context = []): $this->request->attributes = $this->attributes->reveal(); if (!$data) { - $this->metadataFactory // @phpstan-ignore-line + $this->metadataFactory ->create() ->shouldNotBeCalled(); } else { diff --git a/tests/Symfony/Security/ResourceAccessCheckerTest.php b/tests/Symfony/Security/ResourceAccessCheckerTest.php index d452d35ad7c..f87991cdc5c 100644 --- a/tests/Symfony/Security/ResourceAccessCheckerTest.php +++ b/tests/Symfony/Security/ResourceAccessCheckerTest.php @@ -83,19 +83,7 @@ public function testExpressionLanguageNotInstalled(): void $checker->isGranted(Dummy::class, 'is_granted("ROLE_ADMIN")'); } - public function testNotBehindAFirewall(): void - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('The current token must be set to use the "security" attribute (is the URL behind a firewall?).'); - - $authenticationTrustResolverProphecy = $this->prophesize(AuthenticationTrustResolverInterface::class); - $tokenStorageProphecy = $this->prophesize(TokenStorageInterface::class); - - $checker = new ResourceAccessChecker(null, $authenticationTrustResolverProphecy->reveal(), null, $tokenStorageProphecy->reveal()); - $checker->isGranted(Dummy::class, 'is_granted("ROLE_ADMIN")'); - } - - public function testWithoutAuthenticationTokenAndExceptionOnNoTokenIsFalse(): void + public function testWithoutAuthenticationToken(): void { $expressionLanguageProphecy = $this->prophesize(ExpressionLanguage::class); $expressionLanguageProphecy->evaluate('is_granted("ROLE_ADMIN")', Argument::type('array'))->willReturn(true)->shouldBeCalled(); @@ -106,7 +94,7 @@ public function testWithoutAuthenticationTokenAndExceptionOnNoTokenIsFalse(): vo $tokenStorageProphecy->getToken()->willReturn(null); - $checker = new ResourceAccessChecker($expressionLanguageProphecy->reveal(), $authenticationTrustResolverProphecy->reveal(), null, $tokenStorageProphecy->reveal(), $authorizationCheckerProphecy->reveal(), false); + $checker = new ResourceAccessChecker($expressionLanguageProphecy->reveal(), $authenticationTrustResolverProphecy->reveal(), null, $tokenStorageProphecy->reveal(), $authorizationCheckerProphecy->reveal()); self::assertTrue($checker->isGranted(Dummy::class, 'is_granted("ROLE_ADMIN")')); } }