1<?php 2 3declare(strict_types=1); 4 5namespace JMS\Serializer\Tests\Serializer\Doctrine; 6 7use Doctrine\Common\Annotations\AnnotationReader; 8use Doctrine\Common\Annotations\Reader; 9use Doctrine\Common\Persistence\AbstractManagerRegistry; 10use Doctrine\Common\Persistence\ManagerRegistry; 11use Doctrine\DBAL\Connection; 12use Doctrine\DBAL\DriverManager; 13use Doctrine\ORM\Configuration; 14use Doctrine\ORM\EntityManager; 15use Doctrine\ORM\Mapping\Driver\AnnotationDriver; 16use Doctrine\ORM\ORMException; 17use Doctrine\ORM\Tools\SchemaTool; 18use JMS\Serializer\Builder\CallbackDriverFactory; 19use JMS\Serializer\Builder\DefaultDriverFactory; 20use JMS\Serializer\Metadata\Driver\DoctrineTypeDriver; 21use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; 22use JMS\Serializer\Serializer; 23use JMS\Serializer\SerializerBuilder; 24use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Clazz; 25use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Organization; 26use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Person; 27use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\School; 28use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Student; 29use JMS\Serializer\Tests\Fixtures\Doctrine\SingleTableInheritance\Teacher; 30use PHPUnit\Framework\TestCase; 31 32class IntegrationTest extends TestCase 33{ 34 /** @var ManagerRegistry */ 35 private $registry; 36 37 /** @var Serializer */ 38 private $serializer; 39 40 public function testDiscriminatorIsInferredForEntityBaseClass() 41 { 42 $school = new School(); 43 $json = $this->serializer->serialize($school, 'json'); 44 self::assertEquals('{"type":"school"}', $json); 45 46 $deserialized = $this->serializer->deserialize($json, Organization::class, 'json'); 47 self::assertEquals($school, $deserialized); 48 } 49 50 public function testDiscriminatorIsInferredForGenericBaseClass() 51 { 52 $student = new Student(); 53 $json = $this->serializer->serialize($student, 'json'); 54 self::assertEquals('{"type":"student"}', $json); 55 56 $deserialized = $this->serializer->deserialize($json, Person::class, 'json'); 57 self::assertEquals($student, $deserialized); 58 } 59 60 public function testDiscriminatorIsInferredFromDoctrine() 61 { 62 /** @var EntityManager $em */ 63 $em = $this->registry->getManager(); 64 65 $student1 = new Student(); 66 $student2 = new Student(); 67 $teacher = new Teacher(); 68 $class = new Clazz($teacher, [$student1, $student2]); 69 70 $em->persist($student1); 71 $em->persist($student2); 72 $em->persist($teacher); 73 $em->persist($class); 74 $em->flush(); 75 $em->clear(); 76 77 $reloadedClass = $em->find(get_class($class), $class->getId()); 78 self::assertNotSame($class, $reloadedClass); 79 80 $json = $this->serializer->serialize($reloadedClass, 'json'); 81 self::assertEquals('{"id":1,"teacher":{"id":1,"type":"teacher"},"students":[{"id":2,"type":"student"},{"id":3,"type":"student"}]}', $json); 82 } 83 84 protected function setUp() 85 { 86 $connection = $this->createConnection(); 87 $entityManager = $this->createEntityManager($connection); 88 89 $this->registry = $registry = new SimpleManagerRegistry( 90 static function ($id) use ($connection, $entityManager) { 91 switch ($id) { 92 case 'default_connection': 93 return $connection; 94 95 case 'default_manager': 96 return $entityManager; 97 98 default: 99 throw new \RuntimeException(sprintf('Unknown service id "%s".', $id)); 100 } 101 } 102 ); 103 104 $this->serializer = SerializerBuilder::create() 105 ->setMetadataDriverFactory(new CallbackDriverFactory( 106 static function (array $metadataDirs, Reader $annotationReader) use ($registry) { 107 $defaultFactory = new DefaultDriverFactory(new IdenticalPropertyNamingStrategy()); 108 109 return new DoctrineTypeDriver($defaultFactory->createDriver($metadataDirs, $annotationReader), $registry); 110 } 111 )) 112 ->build(); 113 114 $this->prepareDatabase(); 115 } 116 117 private function prepareDatabase() 118 { 119 /** @var EntityManager $em */ 120 $em = $this->registry->getManager(); 121 122 $tool = new SchemaTool($em); 123 $tool->createSchema($em->getMetadataFactory()->getAllMetadata()); 124 } 125 126 private function createConnection() 127 { 128 return DriverManager::getConnection([ 129 'driver' => 'pdo_sqlite', 130 'memory' => true, 131 ]); 132 } 133 134 private function createEntityManager(Connection $con) 135 { 136 $cfg = new Configuration(); 137 $cfg->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader(), [ 138 __DIR__ . '/../../Fixtures/Doctrine/SingleTableInheritance', 139 ])); 140 $cfg->setAutoGenerateProxyClasses(true); 141 $cfg->setProxyNamespace('JMS\Serializer\DoctrineProxy'); 142 $cfg->setProxyDir(sys_get_temp_dir() . '/serializer-test-proxies'); 143 144 return EntityManager::create($con, $cfg); 145 } 146} 147 148class SimpleManagerRegistry extends AbstractManagerRegistry 149{ 150 private $services = []; 151 private $serviceCreator; 152 153 public function __construct($serviceCreator, $name = 'anonymous', array $connections = ['default' => 'default_connection'], array $managers = ['default' => 'default_manager'], $defaultConnection = null, $defaultManager = null, $proxyInterface = 'Doctrine\Common\Persistence\Proxy') 154 { 155 if (null === $defaultConnection) { 156 $defaultConnection = key($connections); 157 } 158 if (null === $defaultManager) { 159 $defaultManager = key($managers); 160 } 161 162 parent::__construct($name, $connections, $managers, $defaultConnection, $defaultManager, $proxyInterface); 163 164 if (!is_callable($serviceCreator)) { 165 throw new \InvalidArgumentException('$serviceCreator must be a valid callable.'); 166 } 167 $this->serviceCreator = $serviceCreator; 168 } 169 170 public function getService($name) 171 { 172 if (isset($this->services[$name])) { 173 return $this->services[$name]; 174 } 175 176 return $this->services[$name] = call_user_func($this->serviceCreator, $name); 177 } 178 179 public function resetService($name) 180 { 181 unset($this->services[$name]); 182 } 183 184 public function getAliasNamespace($alias) 185 { 186 foreach (array_keys($this->getManagers()) as $name) { 187 $manager = $this->getManager($name); 188 189 if ($manager instanceof EntityManager) { 190 try { 191 return $manager->getConfiguration()->getEntityNamespace($alias); 192 } catch (ORMException $ex) { 193 // Probably mapped by another entity manager, or invalid, just ignore this here. 194 } 195 } else { 196 throw new \LogicException(sprintf('Unsupported manager type "%s".', get_class($manager))); 197 } 198 } 199 200 throw new \RuntimeException(sprintf('The namespace alias "%s" is not known to any manager.', $alias)); 201 } 202} 203