Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluated Kdyby_Doctrine_IamTheKingOfHackingNette_* removed #274

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/Kdyby/Doctrine/DI/EntityLocator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

/**
* This file is part of the Kdyby (http://www.kdyby.org)
*
* Copyright (c) 2008 Filip Procházka ([email protected])
* Copyright (c) 2016 Jaroslav Hranička ([email protected])
*
* For the full copyright and license information, please view the file license.txt that was distributed with this source code.
*/

namespace Kdyby\Doctrine\DI;

use Doctrine;
use Kdyby;
use Nette;
use Nette\DI\Container;

class EntityLocator
{

const CACHE_NS = 'Doctrine.EntityLocator';

/** @var Nette\Caching\Cache */
private $cache;

/** @var array */
private $map = [];

public function __construct(Nette\Caching\IStorage $storage)
{
$this->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) {
Copy link
Contributor Author

@hranicka hranicka May 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is extracted code from OrmExtension with minor changes
($config = $this->managerConfigs[$manager]; -> $repository = $classNames[$manager];).

$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);
}
}

}
78 changes: 16 additions & 62 deletions src/Kdyby/Doctrine/DI/OrmExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


Expand Down Expand Up @@ -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(), '\\');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, generated repository services uses EntityLocator for repository to entity class mapping.
DIC generated class must not be overwritten anymore (%entityName%).

$entityArgument = new Statement('$this->getService(?)->get(?)', [$this->prefix('entityLocator'), $repository]);
$this->postCompileRepositoriesQueue[$boundManagers[0]][] = [$repository, $originalServiceName];
}

$builder->removeDefinition($originalServiceName);
Expand Down Expand Up @@ -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,
]);
}


Expand Down