1<?php
2
3declare(strict_types=1);
4
5namespace JMS\Serializer\Tests\Metadata\Driver;
6
7use Doctrine\Common\Annotations\AnnotationReader;
8use Doctrine\ORM\Configuration;
9use Doctrine\ORM\EntityManager;
10use Doctrine\ORM\Mapping\Driver\AnnotationDriver as DoctrineDriver;
11use JMS\Serializer\Metadata\Driver\AnnotationDriver;
12use JMS\Serializer\Metadata\Driver\DoctrineTypeDriver;
13use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy;
14use JMS\Serializer\Tests\Fixtures\Doctrine\BlogPostWithEmbedded;
15use PHPUnit\Framework\TestCase;
16
17class DoctrineDriverTest extends TestCase
18{
19    public function getMetadata()
20    {
21        $refClass = new \ReflectionClass('JMS\Serializer\Tests\Fixtures\Doctrine\BlogPost');
22        return $this->getDoctrineDriver()->loadMetadataForClass($refClass);
23    }
24
25    public function testMetadataForEmbedded()
26    {
27        $refClass = new \ReflectionClass(BlogPostWithEmbedded::class);
28        $meta = $this->getDoctrineDriver()->loadMetadataForClass($refClass);
29        self::assertNotNull($meta);
30    }
31
32    public function testTypelessPropertyIsGivenTypeFromDoctrineMetadata()
33    {
34        $metadata = $this->getMetadata();
35
36        self::assertEquals(
37            ['name' => 'DateTime', 'params' => []],
38            $metadata->propertyMetadata['createdAt']->type
39        );
40    }
41
42    public function testSingleValuedAssociationIsProperlyHinted()
43    {
44        $metadata = $this->getMetadata();
45        self::assertEquals(
46            ['name' => 'JMS\Serializer\Tests\Fixtures\Doctrine\Author', 'params' => []],
47            $metadata->propertyMetadata['author']->type
48        );
49    }
50
51    public function testMultiValuedAssociationIsProperlyHinted()
52    {
53        $metadata = $this->getMetadata();
54
55        self::assertEquals(
56            [
57                'name' => 'ArrayCollection',
58                'params' => [
59                    ['name' => 'JMS\Serializer\Tests\Fixtures\Doctrine\Comment', 'params' => []],
60                ],
61            ],
62            $metadata->propertyMetadata['comments']->type
63        );
64    }
65
66    public function testTypeGuessByDoctrineIsOverwrittenByDelegateDriver()
67    {
68        $metadata = $this->getMetadata();
69
70        // This would be guessed as boolean but we've overriden it to integer
71        self::assertEquals(
72            ['name' => 'integer', 'params' => []],
73            $metadata->propertyMetadata['published']->type
74        );
75    }
76
77    public function testUnknownDoctrineTypeDoesNotResultInAGuess()
78    {
79        $metadata = $this->getMetadata();
80        self::assertNull($metadata->propertyMetadata['slug']->type);
81    }
82
83    public function testNonDoctrineEntityClassIsNotModified()
84    {
85        // Note: Using regular BlogPost fixture here instead of Doctrine fixture
86        // because it has no Doctrine metadata.
87        $refClass = new \ReflectionClass('JMS\Serializer\Tests\Fixtures\BlogPost');
88
89        $plainMetadata = $this->getAnnotationDriver()->loadMetadataForClass($refClass);
90        $doctrineMetadata = $this->getDoctrineDriver()->loadMetadataForClass($refClass);
91
92        // Do not compare timestamps
93        if (abs($doctrineMetadata->createdAt - $plainMetadata->createdAt) < 2) {
94            $plainMetadata->createdAt = $doctrineMetadata->createdAt;
95        }
96
97        self::assertEquals($plainMetadata, $doctrineMetadata);
98    }
99
100    public function testExcludePropertyNoPublicAccessorException()
101    {
102        $first = $this->getAnnotationDriver()
103            ->loadMetadataForClass(new \ReflectionClass('JMS\Serializer\Tests\Fixtures\ExcludePublicAccessor'));
104
105        self::assertArrayHasKey('id', $first->propertyMetadata);
106        self::assertArrayNotHasKey('iShallNotBeAccessed', $first->propertyMetadata);
107    }
108
109    public function testVirtualPropertiesAreNotModified()
110    {
111        $doctrineMetadata = $this->getMetadata();
112        self::assertNull($doctrineMetadata->propertyMetadata['ref']->type);
113    }
114
115    public function testGuidPropertyIsGivenStringType()
116    {
117        $metadata = $this->getMetadata();
118
119        self::assertEquals(
120            ['name' => 'string', 'params' => []],
121            $metadata->propertyMetadata['id']->type
122        );
123    }
124
125    protected function getEntityManager()
126    {
127        $config = new Configuration();
128        $config->setProxyDir(sys_get_temp_dir() . '/JMSDoctrineTestProxies');
129        $config->setProxyNamespace('JMS\Tests\Proxies');
130        $config->setMetadataDriverImpl(
131            new DoctrineDriver(new AnnotationReader(), __DIR__ . '/../../Fixtures/Doctrine')
132        );
133
134        $conn = [
135            'driver' => 'pdo_sqlite',
136            'memory' => true,
137        ];
138
139        return EntityManager::create($conn, $config);
140    }
141
142    public function getAnnotationDriver()
143    {
144        return new AnnotationDriver(new AnnotationReader(), new IdenticalPropertyNamingStrategy());
145    }
146
147    protected function getDoctrineDriver()
148    {
149        $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock();
150        $registry->expects($this->atLeastOnce())
151            ->method('getManagerForClass')
152            ->will($this->returnValue($this->getEntityManager()));
153
154        return new DoctrineTypeDriver(
155            $this->getAnnotationDriver(),
156            $registry
157        );
158    }
159}
160