Skip to content

Commit

Permalink
Replace old annotation loader with the one extracted from LosoBundle.
Browse files Browse the repository at this point in the history
Should be a submodule in the future.
  • Loading branch information
loicfrering committed Sep 29, 2011
1 parent ee77db3 commit 80835d4
Show file tree
Hide file tree
Showing 22 changed files with 735 additions and 336 deletions.
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;
}
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 src/LoSo/LosoBundle/DependencyInjection/Annotations/Repository.php
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 src/LoSo/LosoBundle/DependencyInjection/Annotations/Service.php
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();
}
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);
}
}
71 changes: 71 additions & 0 deletions src/LoSo/LosoBundle/DependencyInjection/Configuration.php
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;
}
}
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;
}
}
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;
}
}
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);
}
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);
}
}
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);
}
}
Loading

0 comments on commit 80835d4

Please sign in to comment.