diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php index 402aca6378b63..06b655328b43d 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php @@ -65,7 +65,7 @@ public function process(ContainerBuilder $container) $processor = new Processor(); foreach ($extensions as $name => $extension) { - if (!$extension instanceof ConfigurationExtensionInterface || !$config = $container->getExtensionConfig($name)) { + if (!$extension instanceof ConfigurationExtensionInterface || !$config = array_filter($container->getExtensionConfig($name))) { // this extension has no semantic configuration or was not called continue; } diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt index 87d656a3fa1eb..391c3e694d974 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt @@ -15,9 +15,9 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (choice_translation_domain ---------------- --------------------%s Allowed values - %s ---------------- --------------------%s - Normalizer Closure%s{ %s + Normalizer Closure%s{%w parameters: 2 %s - file: "%s%eExtension%eCore%eType%eChoiceType.php" + file: "%s%eExtension%eCore%eType%eChoiceType.php"%w line: "%s to %s" %s } %s ---------------- --------------------%s diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt index 967d177c7e9c7..846d6f384684c 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt @@ -8,14 +8,14 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (empty_data) Default Value: null %s %s Closure(s): [ %s - Closure%s{ %s + Closure%s{%w parameters: 1 %s - file: "%s%eExtension%eCore%eType%eFormType.php" + file: "%s%eExtension%eCore%eType%eFormType.php"%w line: "%s to %s" %s }, %s - Closure%s{ %s + Closure%s{%w parameters: 2 %s - file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php" + file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"%w line: "%s to %s" %s } %s ] %s diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt index 0d2e7f44d9bb3..8cc88a550ab70 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt @@ -16,9 +16,9 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (foo) "baz" %s ] %s ---------------- --------------------%s - Normalizer Closure%s{ %s + Normalizer Closure%s{%w parameters: 2 %s - file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php" + file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"%w line: "%s to %s" %s } %s ---------------- --------------------%s diff --git a/src/Symfony/Component/Lock/Tests/Store/SemaphoreStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/SemaphoreStoreTest.php index 7a10ac1f7e76c..6c265b98bdb42 100644 --- a/src/Symfony/Component/Lock/Tests/Store/SemaphoreStoreTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/SemaphoreStoreTest.php @@ -46,13 +46,22 @@ public function testResourceRemoval() private function getOpenedSemaphores() { + if ('Darwin' === PHP_OS) { + $lines = explode(PHP_EOL, trim(`ipcs -s`)); + if (-1 === $start = array_search('Semaphores:', $lines)) { + throw new \Exception('Failed to extract list of opened semaphores. Expected a Semaphore list, got '.implode(PHP_EOL, $lines)); + } + + return \count(\array_slice($lines, ++$start)); + } + $lines = explode(PHP_EOL, trim(`LC_ALL=C ipcs -su`)); if ('------ Semaphore Status --------' !== $lines[0]) { - throw new \Exception('Failed to extract list of opend semaphores. Expect a Semaphore status, got '.implode(PHP_EOL, $lines)); + throw new \Exception('Failed to extract list of opened semaphores. Expected a Semaphore status, got '.implode(PHP_EOL, $lines)); } list($key, $value) = explode(' = ', $lines[1]); if ('used arrays' !== $key) { - throw new \Exception('Failed to extract list of opend semaphores. Expect a used arrays key, got '.implode(PHP_EOL, $lines)); + throw new \Exception('Failed to extract list of opened semaphores. Expected a "used arrays" key, got '.implode(PHP_EOL, $lines)); } return (int) $value; diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 7f8d341846f7d..67c3cd63d8034 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -256,7 +256,7 @@ public function denormalize($data, $class, $format = null, array $context = arra continue; } - $value = $this->validateAndDenormalize($class, $attribute, $value, $format, $context); + $value = $this->validateAndDenormalize(\get_class($class), $attribute, $value, $format, $context); try { $this->setAttributeValue($object, $attribute, $value, $format, $context); } catch (InvalidArgumentException $e) { diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php index bf463fe5457d3..51efe2a559bd9 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php @@ -16,6 +16,7 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\Serializer\Exception\RuntimeException; +use Symfony\Component\Serializer\Mapping\AttributeMetadata; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; @@ -131,4 +132,34 @@ protected function setAttributeValue($object, $attribute, $value, $format = null // Properties not found are ignored } } + + /** + * {@inheritdoc} + */ + protected function getAllowedAttributes($classOrObject, array $context, $attributesAsString = false) + { + if (false === $allowedAttributes = parent::getAllowedAttributes($classOrObject, $context, $attributesAsString)) { + return false; + } + + $discriminatorMapping = $this->classDiscriminatorResolver ? $this->classDiscriminatorResolver->getMappingForMappedObject($classOrObject) : null; + + if (!$discriminatorMapping) { + return $allowedAttributes; + } + + $allowedAttributes[] = $attributesAsString ? $discriminatorMapping->getTypeProperty() : new AttributeMetadata($discriminatorMapping->getTypeProperty()); + + $reflectionClass = new \ReflectionClass($classOrObject); + + if (!$reflectionClass->isAbstract() && !$reflectionClass->isInterface()) { + return $allowedAttributes; + } + + foreach ($discriminatorMapping->getTypesMapping() as $class) { + $allowedAttributes = \array_merge($allowedAttributes, parent::getAllowedAttributes($class, $context, $attributesAsString)); + } + + return \array_unique($allowedAttributes); + } } diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php index f0b4c4d128c38..55bb00bc8e253 100644 --- a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php @@ -15,8 +15,8 @@ /** * @DiscriminatorMap(typeProperty="type", mapping={ - * "first"="Symfony\Component\Serializer\Tests\Fixtures\AbstractDummyFirstChild", - * "second"="Symfony\Component\Serializer\Tests\Fixtures\AbstractDummySecondChild" + * "one"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne", + * "two"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo" * }) * * @author Samuel Roze diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberOne.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberOne.php index 381f7f8a6c70b..200476b54232d 100644 --- a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberOne.php +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberOne.php @@ -11,10 +11,17 @@ namespace Symfony\Component\Serializer\Tests\Fixtures; +use Symfony\Component\Serializer\Annotation\Groups; + /** * @author Samuel Roze */ class DummyMessageNumberOne implements DummyMessageInterface { public $one; + + /** + * @Groups({"two"}) + */ + public $two; } diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberTwo.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberTwo.php new file mode 100644 index 0000000000000..060c10dd7935d --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberTwo.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +/** + * @author Samuel Roze + */ +class DummyMessageNumberTwo implements DummyMessageInterface +{ +} diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 7550b3c9b7ba1..25fbbf38ce584 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -11,11 +11,14 @@ namespace Symfony\Component\Serializer\Tests; +use Doctrine\Common\Annotations\AnnotationReader; use PHPUnit\Framework\TestCase; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping; use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; +use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; @@ -398,11 +401,9 @@ public function testDeserializeAndSerializeInterfacedObjectsWithTheClassMetadata $example = new DummyMessageNumberOne(); $example->one = 1; - $jsonData = '{"message-type":"one","one":1}'; - - $discriminatorResolver = new ClassDiscriminatorFromClassMetadata($this->metadataFactoryMockForDummyInterface()); - $serializer = new Serializer(array(new ObjectNormalizer(null, null, null, null, $discriminatorResolver)), array('json' => new JsonEncoder())); + $jsonData = '{"type":"one","one":1,"two":null}'; + $serializer = $this->serializerWithClassDiscriminator(); $deserialized = $serializer->deserialize($jsonData, DummyMessageInterface::class, 'json'); $this->assertEquals($example, $deserialized); @@ -410,51 +411,48 @@ public function testDeserializeAndSerializeInterfacedObjectsWithTheClassMetadata $this->assertEquals($jsonData, $serialized); } + public function testDeserializeAndSerializeInterfacedObjectsWithTheClassMetadataDiscriminatorResolverAndGroups() + { + $example = new DummyMessageNumberOne(); + $example->two = 2; + + $serializer = $this->serializerWithClassDiscriminator(); + $deserialized = $serializer->deserialize('{"type":"one","one":1,"two":2}', DummyMessageInterface::class, 'json', array( + 'groups' => array('two'), + )); + + $this->assertEquals($example, $deserialized); + + $serialized = $serializer->serialize($deserialized, 'json', array( + 'groups' => array('two'), + )); + + $this->assertEquals('{"two":2,"type":"one"}', $serialized); + } + /** * @expectedException \Symfony\Component\Serializer\Exception\RuntimeException * @expectedExceptionMessage The type "second" has no mapped class for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface" */ public function testExceptionWhenTypeIsNotKnownInDiscriminator() { - $discriminatorResolver = new ClassDiscriminatorFromClassMetadata($this->metadataFactoryMockForDummyInterface()); - $serializer = new Serializer(array(new ObjectNormalizer(null, null, null, null, $discriminatorResolver)), array('json' => new JsonEncoder())); - $serializer->deserialize('{"message-type":"second","one":1}', DummyMessageInterface::class, 'json'); + $this->serializerWithClassDiscriminator()->deserialize('{"type":"second","one":1}', DummyMessageInterface::class, 'json'); } /** * @expectedException \Symfony\Component\Serializer\Exception\RuntimeException - * @expectedExceptionMessage Type property "message-type" not found for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface" + * @expectedExceptionMessage Type property "type" not found for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface" */ public function testExceptionWhenTypeIsNotInTheBodyToDeserialiaze() { - $discriminatorResolver = new ClassDiscriminatorFromClassMetadata($this->metadataFactoryMockForDummyInterface()); - $serializer = new Serializer(array(new ObjectNormalizer(null, null, null, null, $discriminatorResolver)), array('json' => new JsonEncoder())); - $serializer->deserialize('{"one":1}', DummyMessageInterface::class, 'json'); + $this->serializerWithClassDiscriminator()->deserialize('{"one":1}', DummyMessageInterface::class, 'json'); } - private function metadataFactoryMockForDummyInterface() + private function serializerWithClassDiscriminator() { - $factoryMock = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock(); - $factoryMock->method('hasMetadataFor')->will($this->returnValueMap(array( - array( - DummyMessageInterface::class, - true, - ), - ))); - - $factoryMock->method('getMetadataFor')->will($this->returnValueMap(array( - array( - DummyMessageInterface::class, - new ClassMetadata( - DummyMessageInterface::class, - new ClassDiscriminatorMapping('message-type', array( - 'one' => DummyMessageNumberOne::class, - )) - ), - ), - ))); + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - return $factoryMock; + return new Serializer(array(new ObjectNormalizer($classMetadataFactory, null, null, null, new ClassDiscriminatorFromClassMetadata($classMetadataFactory))), array('json' => new JsonEncoder())); } } diff --git a/src/Symfony/Component/Workflow/Event/Event.php b/src/Symfony/Component/Workflow/Event/Event.php index 943a4da5a681e..a9e20869682b3 100644 --- a/src/Symfony/Component/Workflow/Event/Event.php +++ b/src/Symfony/Component/Workflow/Event/Event.php @@ -30,10 +30,10 @@ class Event extends BaseEvent private $workflowName; /** - * @param object $subject - * @param Marking $marking - * @param Transition $transition - * @param Workflow $workflow + * @param object $subject + * @param Marking $marking + * @param Transition $transition + * @param WorkflowInterface $workflow */ public function __construct($subject, Marking $marking, Transition $transition, $workflow = null) {