-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replace old annotation loader with the one extracted from LosoBundle.
Should be a submodule in the future.
- Loading branch information
1 parent
ee77db3
commit 80835d4
Showing
22 changed files
with
735 additions
and
336 deletions.
There are no files selected for viewing
3 changes: 2 additions & 1 deletion
3
...njection/Loader/Annotation/Controller.php → ...dencyInjection/Annotations/Controller.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
<?php | ||
|
||
namespace LoSo\Symfony\Component\DependencyInjection\Loader\Annotation; | ||
namespace LoSo\LosoBundle\DependencyInjection\Annotations; | ||
|
||
use Doctrine\Common\Annotations\Annotation; | ||
|
||
final class Controller extends Annotation | ||
{ | ||
public $name; | ||
} |
9 changes: 9 additions & 0 deletions
9
src/LoSo/LosoBundle/DependencyInjection/Annotations/Inject.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?php | ||
|
||
namespace LoSo\LosoBundle\DependencyInjection\Annotations; | ||
|
||
use Doctrine\Common\Annotations\Annotation; | ||
|
||
final class Inject extends Annotation | ||
{ | ||
} |
12 changes: 12 additions & 0 deletions
12
src/LoSo/LosoBundle/DependencyInjection/Annotations/Repository.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?php | ||
|
||
namespace LoSo\LosoBundle\DependencyInjection\Annotations; | ||
|
||
use Doctrine\Common\Annotations\Annotation; | ||
|
||
final class Repository extends Annotation | ||
{ | ||
public $entity; | ||
public $entityManager; | ||
public $name; | ||
} |
17 changes: 17 additions & 0 deletions
17
src/LoSo/LosoBundle/DependencyInjection/Annotations/Service.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
namespace LoSo\LosoBundle\DependencyInjection\Annotations; | ||
|
||
use Doctrine\Common\Annotations\Annotation; | ||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
|
||
final class Service extends Annotation | ||
{ | ||
public $name; | ||
public $scope = ContainerInterface::SCOPE_CONTAINER; | ||
public $public; | ||
public $configurator; | ||
public $factoryMethod; | ||
public $factoryService; | ||
public $tags = array(); | ||
} |
45 changes: 45 additions & 0 deletions
45
src/LoSo/LosoBundle/DependencyInjection/Compiler/RepositoryDefinitionPass.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php | ||
|
||
namespace LoSo\LosoBundle\DependencyInjection\Compiler; | ||
|
||
use LoSo\LosoBundle\DependencyInjection\Loader\Annotation\DoctrineServicesUtils; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; | ||
|
||
/** | ||
* CompilerPass which registers Doctrine entity metadatas necessary | ||
* for repositories into the container. | ||
* | ||
* @author Loïc Frering <loic.frering@gmail.com> | ||
*/ | ||
class RepositoryDefinitionPass implements CompilerPassInterface | ||
{ | ||
private $doctrineServicesUtils; | ||
|
||
public function process(ContainerBuilder $container) | ||
{ | ||
$this->doctrineServiceUtils = new DoctrineServicesUtils(); | ||
|
||
foreach ($container->findTaggedServiceIds('loso.doctrine.repository') as $repositoryId => $tag) { | ||
$entity = $tag[0]['entity']; | ||
$entityManager = $tag[0]['entityManager']; | ||
|
||
$this->processRepositoryDefinition($entity, $entityManager, $container->getDefinition($repositoryId)); | ||
$this->registerEntityMetadata($entity, $entityManager, $container); | ||
} | ||
} | ||
|
||
private function processRepositoryDefinition($entity, $entityManager, $definition) | ||
{ | ||
$entityManagerRef = $this->doctrineServiceUtils->getEntityManagerReference($entityManager); | ||
$entityMetadataRef = $this->doctrineServiceUtils->getEntityMetadataReference($entity, $entityManager); | ||
$definition->setArguments(array($entityManagerRef, $entityMetadataRef)); | ||
} | ||
|
||
private function registerEntityMetadata($entity, $entityManager, $container) | ||
{ | ||
$definition = $this->doctrineServiceUtils->getEntityMetadataDefinition($entity, $entityManager); | ||
$id = $this->doctrineServiceUtils->resolveEntityMetadataId($entity, $entityManager); | ||
$container->setDefinition($id, $definition); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
namespace LoSo\LosoBundle\DependencyInjection; | ||
|
||
use Symfony\Component\Config\Definition\Builder\TreeBuilder; | ||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; | ||
use Symfony\Component\Config\Definition\ConfigurationInterface; | ||
|
||
/** | ||
* @author Loïc Frering <loic.frering@gmail.com> | ||
*/ | ||
class Configuration implements ConfigurationInterface | ||
{ | ||
private $bundles; | ||
|
||
public function __construct(array $bundles) | ||
{ | ||
$this->bundles = $bundles; | ||
} | ||
|
||
public function getConfigTreeBuilder() | ||
{ | ||
$bundles = $this->bundles; | ||
|
||
$builder = new TreeBuilder(); | ||
$rootNode = $builder->root('loso'); | ||
|
||
$rootNode | ||
->children() | ||
->arrayNode('service_scan') | ||
->requiresAtLeastOneElement() | ||
->useAttributeAsKey('scan') | ||
->beforeNormalization() | ||
->always() | ||
->then(function($v) use ($bundles) { | ||
foreach($v as $scan => $value) { | ||
$v[$scan]['is_bundle'] = in_array($scan, $bundles); | ||
} | ||
return $v; | ||
}) | ||
->end() | ||
->prototype('array') | ||
->validate() | ||
->ifTrue(function($v) { return $v['is_bundle'] && !empty($v['dir']); }) | ||
->thenInvalid('"dir" must not be set for a bundle.') | ||
->end() | ||
->validate() | ||
->ifTrue(function($v) { return !$v['is_bundle'] && !empty($v['base_namespace']); }) | ||
->thenInvalid('"base_namespace" must only be set for a bundle.') | ||
->end() | ||
->validate() | ||
->ifTrue(function($v) { return !$v['is_bundle'] && empty($v['dir']); }) | ||
->thenInvalid('"dir" must be set for arbitrary keys, define bundles otherwise.') | ||
->end() | ||
->children() | ||
->booleanNode('is_bundle')->end() | ||
->arrayNode('base_namespace') | ||
->beforeNormalization()->ifString()->then(function($v) { return array($v); })->end() | ||
->prototype('scalar')->end() | ||
->end() | ||
->arrayNode('dir') | ||
->beforeNormalization()->ifString()->then(function($v) { return array($v); })->end() | ||
->prototype('scalar')->end() | ||
->end() | ||
->end() | ||
->end() | ||
->end() | ||
->end(); | ||
|
||
return $builder; | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
...encyInjection/Loader/Annotation/DefinitionBuilder/AbstractAnnotationDefinitionBuilder.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
namespace LoSo\LosoBundle\DependencyInjection\Loader\Annotation\DefinitionBuilder; | ||
|
||
use Doctrine\Common\Annotations\AnnotationReader; | ||
|
||
/** | ||
* @author Loïc Frering <loic.frering@gmail.com> | ||
*/ | ||
abstract class AbstractAnnotationDefinitionBuilder implements AnnotationDefinitionBuilderInterface | ||
{ | ||
protected $reader; | ||
|
||
public function __construct(AnnotationReader $reader) | ||
{ | ||
$this->reader = $reader; | ||
} | ||
} |
124 changes: 124 additions & 0 deletions
124
...endencyInjection/Loader/Annotation/DefinitionBuilder/AbstractServiceDefinitionBuilder.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
<?php | ||
|
||
namespace LoSo\LosoBundle\DependencyInjection\Loader\Annotation\DefinitionBuilder; | ||
|
||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
use Symfony\Component\DependencyInjection\Definition; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
|
||
/** | ||
* @author Loïc Frering <loic.frering@gmail.com> | ||
*/ | ||
abstract class AbstractServiceDefinitionBuilder extends AbstractAnnotationDefinitionBuilder | ||
{ | ||
private static $injectAnnot = 'LoSo\LosoBundle\DependencyInjection\Annotations\Inject'; | ||
|
||
public function build(\ReflectionClass $reflClass, $annot) | ||
{ | ||
$definition = new Definition($reflClass->getName()); | ||
|
||
if (null !== ($constructor = $reflClass->getConstructor())) { | ||
$this->processConstructor($constructor, $definition); | ||
} | ||
$this->processProperties($reflClass->getProperties(), $definition); | ||
$this->processMethods($reflClass->getMethods(), $definition, $reflClass); | ||
|
||
return array('id' => null, 'definition' => $definition); | ||
} | ||
|
||
private function processConstructor($constructor, $definition) | ||
{ | ||
if ($annot = $this->reader->getMethodAnnotation($constructor, self::$injectAnnot)) { | ||
$arguments = $this->extractReferencesForMethod($constructor, $annot); | ||
$definition->setArguments($arguments); | ||
} | ||
} | ||
|
||
private function processProperties($properties, $definition) | ||
{ | ||
foreach ($properties as $property) { | ||
if ($annot = $this->reader->getPropertyAnnotation($property, self::$injectAnnot)) { | ||
$propertyName = $this->filterUnderscore($property->getName()); | ||
$reference = $this->extractReferenceForProperty($property, $annot); | ||
$definition->addMethodCall('set' . ucfirst($propertyName), array($reference)); | ||
} | ||
} | ||
} | ||
|
||
private function processMethods($methods, $definition, $reflClass) | ||
{ | ||
foreach ($methods as $method) { | ||
if (strpos($method->getName(), 'set') === 0) { | ||
if ($annot = $this->reader->getMethodAnnotation($method, self::$injectAnnot)) { | ||
$arguments = $this->extractReferencesForMethod($method, $annot); | ||
$definition->addMethodCall($method->getName(), $arguments); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private function extractReferencesForMethod($method, $annot) | ||
{ | ||
$arguments = array(); | ||
$parameters = $method->getParameters(); | ||
if (null === $annot->value) { | ||
foreach ($parameters as $parameter) { | ||
$arguments[] = new Reference($parameter->getName()); | ||
} | ||
} | ||
else { | ||
if (!is_array($annot->value)) { | ||
$annot->value = array($annot->value); | ||
} | ||
if (count($annot->value) != $method->getNumberOfParameters()) { | ||
throw new \InvalidArgumentException(sprintf('Annotation "@Inject" when specifying services id must have one id per method argument for "%s::%s"', $method->getDeclaringClass()->getName(), $method->getName())); | ||
} | ||
$arguments = $this->resolveServices($annot->value); | ||
} | ||
return $arguments; | ||
} | ||
|
||
private function extractReferenceForProperty($property, $annot) | ||
{ | ||
if ($annot->value) { | ||
if (!is_string($annot->value)) { | ||
throw new \InvalidArgumentException(sprintf('Annotation "@Inject" when specifying services id on property must have one string value for "%s::%s"', $property->getDeclaringClass()->getName(), $property->getName())); | ||
} | ||
return $this->resolveServices($annot->value); | ||
} | ||
return new Reference($this->filterUnderscore($property->getName())); | ||
} | ||
|
||
private function resolveServices($value) | ||
{ | ||
if (is_array($value)) { | ||
$value = array_map(array($this, 'resolveServices'), $value); | ||
} else if (is_string($value) && false === strpos($value, '%')) { | ||
if (0 === strpos($value, '?')) { | ||
$value = substr($value, 1); | ||
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; | ||
} else { | ||
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; | ||
} | ||
|
||
if ('=' === substr($value, -1)) { | ||
$value = substr($value, 0, -1); | ||
$strict = false; | ||
} else { | ||
$strict = true; | ||
} | ||
|
||
$value = new Reference($value, $invalidBehavior, $strict); | ||
} | ||
|
||
return $value; | ||
} | ||
|
||
private function filterUnderscore($value) | ||
{ | ||
if(strpos($value, '_') === 0) { | ||
return substr($value, 1); | ||
} | ||
return $value; | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
...ncyInjection/Loader/Annotation/DefinitionBuilder/AnnotationDefinitionBuilderInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?php | ||
|
||
namespace LoSo\LosoBundle\DependencyInjection\Loader\Annotation\DefinitionBuilder; | ||
|
||
interface AnnotationDefinitionBuilderInterface | ||
{ | ||
public function build(\ReflectionClass $reflClass, $annot); | ||
} |
28 changes: 28 additions & 0 deletions
28
...e/DependencyInjection/Loader/Annotation/DefinitionBuilder/ControllerDefinitionBuilder.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
namespace LoSo\LosoBundle\DependencyInjection\Loader\Annotation\DefinitionBuilder; | ||
|
||
use LoSo\LosoBundle\DependencyInjection\Loader\Annotation\ServiceIdGenerator; | ||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
|
||
/** | ||
* @author Loïc Frering <loic.frering@gmail.com> | ||
*/ | ||
class ControllerDefinitionBuilder extends AbstractServiceDefinitionBuilder | ||
{ | ||
public function build(\ReflectionClass $reflClass, $annot) | ||
{ | ||
$definitionHolder = parent::build($reflClass, $annot); | ||
$definition = $definitionHolder['definition']; | ||
$id = $annot->value ?: $annot->name; | ||
if (empty($id)) { | ||
$serviceIdGenerator = new ServiceIdGenerator(); | ||
$id = $serviceIdGenerator->generate($reflClass); | ||
} | ||
|
||
$definition->addTag('loso.controller'); | ||
|
||
return array('id' => $id, 'definition' => $definition); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
...e/DependencyInjection/Loader/Annotation/DefinitionBuilder/RepositoryDefinitionBuilder.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?php | ||
|
||
namespace LoSo\LosoBundle\DependencyInjection\Loader\Annotation\DefinitionBuilder; | ||
|
||
use LoSo\LosoBundle\DependencyInjection\Loader\Annotation\ServiceIdGenerator; | ||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
|
||
/** | ||
* @author Loïc Frering <loic.frering@gmail.com> | ||
*/ | ||
class RepositoryDefinitionBuilder extends AbstractServiceDefinitionBuilder | ||
{ | ||
public function build(\ReflectionClass $reflClass, $annot) | ||
{ | ||
$definitionHolder = parent::build($reflClass, $annot); | ||
$definition = $definitionHolder['definition']; | ||
$id = $annot->name; | ||
if (empty($id)) { | ||
$serviceIdGenerator = new ServiceIdGenerator(); | ||
$id = $serviceIdGenerator->generate($reflClass); | ||
} | ||
|
||
$entity = $annot->value ?: $annot->entity; | ||
$entityManager = !empty($annot->entityManager) ? $annot->entityManager : 'default'; | ||
if (null === $entity) { | ||
throw new \InvalidArgumentException(sprintf('Entity name must be setted in @Repository for class "%s".', $reflClass->getName())); | ||
} | ||
|
||
$definition->addTag('loso.doctrine.repository', array( | ||
'entity' => $entity, | ||
'entityManager' => $entityManager | ||
)); | ||
|
||
return array('id' => $id, 'definition' => $definition); | ||
} | ||
} |
Oops, something went wrong.