Repository: symfony/symfony
File: src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php (PHP)

Code before:
    {
        $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
        $normalizer = new ObjectNormalizer($classMetadataFactory);

        $object = new ObjectWithPropertyAndAccessorSameName(
            'foo',
            'getFoo',
            'canFoo',
            'hasFoo',
            'isFoo'
        );
        $normalized = $normalizer->normalize($object);

        // Previously, only the 'foo' property was extracted, all other properties starting with accessor verbs were
        // converted to 'foo'. Now accessor methods with exactly the same name as the property take precedence.
        $this->assertSame([
            'getFoo' => 'getFoo',
            'canFoo' => 'canFoo',
            'hasFoo' => 'hasFoo',
            'isFoo' => 'isFoo',
            // The getFoo accessor method is used for foo, thus it's also 'getFoo' instead of 'foo'
            'foo' => 'getFoo',
        ], $normalized);

        $denormalized = $this->normalizer->denormalize($normalized, ObjectWithPropertyAndAccessorSameName::class);

        $this->assertSame('getFoo', $denormalized->getFoo());

        // On the initial object the value was 'foo', but the normalizer prefers the accessor method 'getFoo'
        // Thus on the denoramilzed object the value is 'getFoo'
        $this->assertSame('foo', $object->foo);
        $this->assertSame('getFoo', $denormalized->foo);

        $this->assertSame('hasFoo', $denormalized->hasFoo());
        $this->assertSame('canFoo', $denormalized->canFoo());
        $this->assertSame('isFoo', $denormalized->isFoo());
    }

    /**
     * Priority of accessor methods is defined by the PropertyReadInfoExtractorInterface passed to the PropertyAccessor
     * component. By default ReflectionExtractor::$defaultAccessorPrefixes are used.
     */
    public function testPrecedenceOfAccessorMethods()
    {
        $createObjectNormalizer = function ($accessorPrefixes) {
            $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
            $propertyAccessorBuilder = (new PropertyAccessorBuilder())
                ->setReadInfoExtractor(
                    new ReflectionExtractor([], $accessorPrefixes, null, false)
                );
            return new ObjectNormalizer(

Review comment (suggestion):
"Previously" won't mean anything once merged, this should be reformulated to not refer to something that won't last

Code after:

        $object = new ObjectWithPropertyAndAllAccessorMethods(
            'foo',
        );
        $normalized = $normalizer->normalize($object);

        // The getter method should take precedence over all other accessor methods
        $this->assertSame([
            'foo' => 'foo',
        ], $normalized);
    }

    public function testNormalizeObjectWithPropertyAndAccessorMethodsWithSameName()
    {
        $normalizer = $this->getNormalizerForAccessors();

        $object = new ObjectWithPropertyAndAccessorSameName(
            'foo',
            'getFoo',
            'canFoo',
            'hasFoo',
            'isFoo'
        );
        $normalized = $normalizer->normalize($object);

        // Accessor methods with exactly the same name as the property should take precedence
        $this->assertSame([
            'getFoo' => 'getFoo',
            'canFoo' => 'canFoo',
            'hasFoo' => 'hasFoo',
            'isFoo' => 'isFoo',
            // The getFoo accessor method is used for foo, thus it's also 'getFoo' instead of 'foo'
            'foo' => 'getFoo',
        ], $normalized);

        $denormalized = $this->normalizer->denormalize($normalized, ObjectWithPropertyAndAccessorSameName::class);

        $this->assertSame('getFoo', $denormalized->getFoo());

        // On the initial object the value was 'foo', but the normalizer prefers the accessor method 'getFoo'
        // Thus on the denoramilzed object the value is 'getFoo'
        $this->assertSame('foo', $object->foo);
        $this->assertSame('getFoo', $denormalized->foo);

        $this->assertSame('hasFoo', $denormalized->hasFoo());
        $this->assertSame('canFoo', $denormalized->canFoo());
        $this->assertSame('isFoo', $denormalized->isFoo());
    }

    /**
     * Priority of accessor methods is defined by the PropertyReadInfoExtractorInterface passed to the PropertyAccessor