diff --git a/src/Kdyby/Doctrine/DI/EntityLocator.php b/src/Kdyby/Doctrine/DI/EntityLocator.php new file mode 100644 index 00000000..eecf8db5 --- /dev/null +++ b/src/Kdyby/Doctrine/DI/EntityLocator.php @@ -0,0 +1,85 @@ +cache = new Nette\Caching\Cache($storage, self::CACHE_NS); + } + + public function setup(Container $container, $containerFile, array $queue, array $classNames, array $managers) + { + if (empty($queue)) { + return; + } + + $this->map = $this->cache->load($containerFile); + + if ($this->map === NULL) { + foreach ($queue as $manager => $items) { + $repository = $classNames[$manager]; + /** @var Kdyby\Doctrine\EntityManager $entityManager */ + $entityManager = $container->getService($managers[$manager]); + /** @var Doctrine\ORM\Mapping\ClassMetadata $entityMetadata */ + $metadataFactory = $entityManager->getMetadataFactory(); + + $allMetadata = []; + foreach ($metadataFactory->getAllMetadata() as $entityMetadata) { + if ($repository === $entityMetadata->customRepositoryClassName || empty($entityMetadata->customRepositoryClassName)) { + continue; + } + + $allMetadata[ltrim($entityMetadata->customRepositoryClassName, '\\')] = $entityMetadata; + } + + foreach ($items as $item) { + if (!isset($allMetadata[$item[0]])) { + throw new Nette\Utils\AssertionException(sprintf('Repository class %s have been found in DIC, but no entity has it assigned and it has no entity configured', $item[0])); + } + + $entityMetadata = $allMetadata[$item[0]]; + $this->map[$item[0]] = $entityMetadata->getName(); + } + } + + $this->cache->save($containerFile, $this->map, [ + Nette\Caching\Cache::FILES => [$containerFile], + ]); + } + } + + public function get($repositoryName) + { + if (isset($this->map[$repositoryName])) { + return $this->map[$repositoryName]; + } else { + throw new Kdyby\Doctrine\InvalidArgumentException('Entity for repository %s was not found.', $repositoryName); + } + } + +} diff --git a/src/Kdyby/Doctrine/DI/OrmExtension.php b/src/Kdyby/Doctrine/DI/OrmExtension.php index 3bb6e6cb..7202a609 100644 --- a/src/Kdyby/Doctrine/DI/OrmExtension.php +++ b/src/Kdyby/Doctrine/DI/OrmExtension.php @@ -207,6 +207,10 @@ public function loadConfiguration() $builder->parameters[$this->name]['dbal']['defaultConnection'], $builder->parameters[$this->name]['orm']['defaultEntityManager'], ]); + + $builder->addDefinition($this->prefix('entityLocator')) + ->setClass('Kdyby\Doctrine\DI\EntityLocator') + ->setAutowired(FALSE); } @@ -706,8 +710,9 @@ protected function processRepositories() $entityArgument = $boundEntity; } else { - $entityArgument = new Code\PhpLiteral('"%entityName%"'); - $this->postCompileRepositoriesQueue[$boundManagers[0]][] = [ltrim($originalDef->getClass(), '\\'), $originalServiceName]; + $repository = ltrim($originalDef->getClass(), '\\'); + $entityArgument = new Statement('$this->getService(?)->get(?)', [$this->prefix('entityLocator'), $repository]); + $this->postCompileRepositoriesQueue[$boundManagers[0]][] = [$repository, $originalServiceName]; } $builder->removeDefinition($originalServiceName); @@ -773,67 +778,16 @@ public function afterCompile(Code\ClassType $class) $init->addBody($originalInitialize); } - $this->processRepositoryFactoryEntities($class); - } - - - - protected function processRepositoryFactoryEntities(Code\ClassType $class) - { - if (empty($this->postCompileRepositoriesQueue)) { - return; - } - - $dic = self::evalAndInstantiateContainer($class); - - foreach ($this->postCompileRepositoriesQueue as $manager => $items) { - $config = $this->managerConfigs[$manager]; - /** @var Kdyby\Doctrine\EntityManager $entityManager */ - $entityManager = $dic->getService($this->configuredManagers[$manager]); - /** @var Doctrine\ORM\Mapping\ClassMetadata $entityMetadata */ - $metadataFactory = $entityManager->getMetadataFactory(); - - $allMetadata = []; - foreach ($metadataFactory->getAllMetadata() as $entityMetadata) { - if ($config['defaultRepositoryClassName'] === $entityMetadata->customRepositoryClassName || empty($entityMetadata->customRepositoryClassName)) { - continue; - } - - $allMetadata[ltrim($entityMetadata->customRepositoryClassName, '\\')] = $entityMetadata; - } - - foreach ($items as $item) { - if (!isset($allMetadata[$item[0]])) { - throw new Nette\Utils\AssertionException(sprintf('Repository class %s have been found in DIC, but no entity has it assigned and it has no entity configured', $item[0])); - } - - $entityMetadata = $allMetadata[$item[0]]; - $serviceMethod = Nette\DI\Container::getMethodName($item[1]); - - $method = $class->getMethod($serviceMethod); - $methodBody = $method->getBody(); - $method->setBody(str_replace('"%entityName%"', Code\Helpers::format('?', $entityMetadata->getName()), $methodBody)); - } - } - } - - - - /** - * @param Code\ClassType $class - * @return Nette\DI\Container - */ - private static function evalAndInstantiateContainer(Code\ClassType $class) - { - $classCopy = clone $class; - $classCopy->setName($className = 'Kdyby_Doctrine_IamTheKingOfHackingNette_' . $class->getName() . '_' . rand()); - - $containerCode = "$classCopy"; + $classNames = array_map(function ($config) { + return $config['defaultRepositoryClassName']; + }, $this->managerConfigs); - return call_user_func(function () use ($className, $containerCode) { - eval($containerCode); - return new $className(); - }); + $init->addBody('$this->getService(?)->setup($this, __FILE__, ?, ?, ?);', [ + $this->prefix('entityLocator'), + $this->postCompileRepositoriesQueue, + $classNames, + $this->configuredManagers, + ]); }