Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,477 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Doctrine\DependencyInjection;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
/**
* This abstract classes groups common code that Doctrine Object Manager extensions (ORM, MongoDB, CouchDB) need.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
abstract class AbstractDoctrineExtension extends Extension
{
/**
* Used inside metadata driver method to simplify aggregation of data.
*/
protected $aliasMap = array();
/**
* Used inside metadata driver method to simplify aggregation of data.
*/
protected $drivers = array();
/**
* @param array $objectManager A configured object manager
* @param ContainerBuilder $container A ContainerBuilder instance
*
* @throws \InvalidArgumentException
*/
protected function loadMappingInformation(array $objectManager, ContainerBuilder $container)
{
if ($objectManager['auto_mapping']) {
// automatically register bundle mappings
foreach (array_keys($container->getParameter('kernel.bundles')) as $bundle) {
if (!isset($objectManager['mappings'][$bundle])) {
$objectManager['mappings'][$bundle] = array(
'mapping' => true,
'is_bundle' => true,
);
}
}
}
foreach ($objectManager['mappings'] as $mappingName => $mappingConfig) {
if (null !== $mappingConfig && false === $mappingConfig['mapping']) {
continue;
}
$mappingConfig = array_replace(array(
'dir' => false,
'type' => false,
'prefix' => false,
), (array) $mappingConfig);
$mappingConfig['dir'] = $container->getParameterBag()->resolveValue($mappingConfig['dir']);
// a bundle configuration is detected by realizing that the specified dir is not absolute and existing
if (!isset($mappingConfig['is_bundle'])) {
$mappingConfig['is_bundle'] = !is_dir($mappingConfig['dir']);
}
if ($mappingConfig['is_bundle']) {
$bundle = null;
foreach ($container->getParameter('kernel.bundles') as $name => $class) {
if ($mappingName === $name) {
$bundle = new \ReflectionClass($class);
break;
}
}
if (null === $bundle) {
throw new \InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled.', $mappingName));
}
$mappingConfig = $this->getMappingDriverBundleConfigDefaults($mappingConfig, $bundle, $container);
if (!$mappingConfig) {
continue;
}
}
$this->assertValidMappingConfiguration($mappingConfig, $objectManager['name']);
$this->setMappingDriverConfig($mappingConfig, $mappingName);
$this->setMappingDriverAlias($mappingConfig, $mappingName);
}
}
/**
* Register the alias for this mapping driver.
*
* Aliases can be used in the Query languages of all the Doctrine object managers to simplify writing tasks.
*
* @param array $mappingConfig
* @param string $mappingName
*/
protected function setMappingDriverAlias($mappingConfig, $mappingName)
{
if (isset($mappingConfig['alias'])) {
$this->aliasMap[$mappingConfig['alias']] = $mappingConfig['prefix'];
} else {
$this->aliasMap[$mappingName] = $mappingConfig['prefix'];
}
}
/**
* Register the mapping driver configuration for later use with the object managers metadata driver chain.
*
* @param array $mappingConfig
* @param string $mappingName
*
* @throws \InvalidArgumentException
*/
protected function setMappingDriverConfig(array $mappingConfig, $mappingName)
{
$mappingDirectory = $mappingConfig['dir'];
if (!is_dir($mappingDirectory)) {
throw new \InvalidArgumentException(sprintf('Invalid Doctrine mapping path given. Cannot load Doctrine mapping/bundle named "%s".', $mappingName));
}
$this->drivers[$mappingConfig['type']][$mappingConfig['prefix']] = realpath($mappingDirectory) ?: $mappingDirectory;
}
/**
* If this is a bundle controlled mapping all the missing information can be autodetected by this method.
*
* Returns false when autodetection failed, an array of the completed information otherwise.
*
* @return array|false
*/
protected function getMappingDriverBundleConfigDefaults(array $bundleConfig, \ReflectionClass $bundle, ContainerBuilder $container)
{
$bundleDir = \dirname($bundle->getFileName());
if (!$bundleConfig['type']) {
$bundleConfig['type'] = $this->detectMetadataDriver($bundleDir, $container);
}
if (!$bundleConfig['type']) {
// skip this bundle, no mapping information was found.
return false;
}
if (!$bundleConfig['dir']) {
if (\in_array($bundleConfig['type'], array('annotation', 'staticphp'))) {
$bundleConfig['dir'] = $bundleDir.'/'.$this->getMappingObjectDefaultName();
} else {
$bundleConfig['dir'] = $bundleDir.'/'.$this->getMappingResourceConfigDirectory();
}
} else {
$bundleConfig['dir'] = $bundleDir.'/'.$bundleConfig['dir'];
}
if (!$bundleConfig['prefix']) {
$bundleConfig['prefix'] = $bundle->getNamespaceName().'\\'.$this->getMappingObjectDefaultName();
}
return $bundleConfig;
}
/**
* Register all the collected mapping information with the object manager by registering the appropriate mapping drivers.
*
* @param array $objectManager
* @param ContainerBuilder $container A ContainerBuilder instance
*/
protected function registerMappingDrivers($objectManager, ContainerBuilder $container)
{
// configure metadata driver for each bundle based on the type of mapping files found
if ($container->hasDefinition($this->getObjectManagerElementName($objectManager['name'].'_metadata_driver'))) {
$chainDriverDef = $container->getDefinition($this->getObjectManagerElementName($objectManager['name'].'_metadata_driver'));
} else {
$chainDriverDef = new Definition('%'.$this->getObjectManagerElementName('metadata.driver_chain.class%'));
$chainDriverDef->setPublic(false);
}
foreach ($this->drivers as $driverType => $driverPaths) {
$mappingService = $this->getObjectManagerElementName($objectManager['name'].'_'.$driverType.'_metadata_driver');
if ($container->hasDefinition($mappingService)) {
$mappingDriverDef = $container->getDefinition($mappingService);
$args = $mappingDriverDef->getArguments();
if ('annotation' == $driverType) {
$args[1] = array_merge(array_values($driverPaths), $args[1]);
} else {
$args[0] = array_merge(array_values($driverPaths), $args[0]);
}
$mappingDriverDef->setArguments($args);
} elseif ('annotation' == $driverType) {
$mappingDriverDef = new Definition('%'.$this->getObjectManagerElementName('metadata.'.$driverType.'.class%'), array(
new Reference($this->getObjectManagerElementName('metadata.annotation_reader')),
array_values($driverPaths),
));
} else {
$mappingDriverDef = new Definition('%'.$this->getObjectManagerElementName('metadata.'.$driverType.'.class%'), array(
array_values($driverPaths),
));
}
$mappingDriverDef->setPublic(false);
if (false !== strpos($mappingDriverDef->getClass(), 'yml') || false !== strpos($mappingDriverDef->getClass(), 'xml')) {
$mappingDriverDef->setArguments(array(array_flip($driverPaths)));
$mappingDriverDef->addMethodCall('setGlobalBasename', array('mapping'));
}
$container->setDefinition($mappingService, $mappingDriverDef);
foreach ($driverPaths as $prefix => $driverPath) {
$chainDriverDef->addMethodCall('addDriver', array(new Reference($mappingService), $prefix));
}
}
$container->setDefinition($this->getObjectManagerElementName($objectManager['name'].'_metadata_driver'), $chainDriverDef);
}
/**
* Assertion if the specified mapping information is valid.
*
* @param array $mappingConfig
* @param string $objectManagerName
*
* @throws \InvalidArgumentException
*/
protected function assertValidMappingConfiguration(array $mappingConfig, $objectManagerName)
{
if (!$mappingConfig['type'] || !$mappingConfig['dir'] || !$mappingConfig['prefix']) {
throw new \InvalidArgumentException(sprintf('Mapping definitions for Doctrine manager "%s" require at least the "type", "dir" and "prefix" options.', $objectManagerName));
}
if (!is_dir($mappingConfig['dir'])) {
throw new \InvalidArgumentException(sprintf('Specified non-existing directory "%s" as Doctrine mapping source.', $mappingConfig['dir']));
}
if (!\in_array($mappingConfig['type'], array('xml', 'yml', 'annotation', 'php', 'staticphp'))) {
throw new \InvalidArgumentException(sprintf('Can only configure "xml", "yml", "annotation", "php" or '.
'"staticphp" through the DoctrineBundle. Use your own bundle to configure other metadata drivers. '.
'You can register them by adding a new driver to the '.
'"%s" service definition.', $this->getObjectManagerElementName($objectManagerName.'_metadata_driver')
));
}
}
/**
* Detects what metadata driver to use for the supplied directory.
*
* @param string $dir A directory path
* @param ContainerBuilder $container A ContainerBuilder instance
*
* @return string|null A metadata driver short name, if one can be detected
*/
protected function detectMetadataDriver($dir, ContainerBuilder $container)
{
// add the closest existing directory as a resource
$configPath = $this->getMappingResourceConfigDirectory();
$resource = $dir.'/'.$configPath;
while (!is_dir($resource)) {
$resource = \dirname($resource);
}
$container->addResource(new FileResource($resource));
$extension = $this->getMappingResourceExtension();
if (($files = glob($dir.'/'.$configPath.'/*.'.$extension.'.xml')) && \count($files)) {
return 'xml';
} elseif (($files = glob($dir.'/'.$configPath.'/*.'.$extension.'.yml')) && \count($files)) {
return 'yml';
} elseif (($files = glob($dir.'/'.$configPath.'/*.'.$extension.'.php')) && \count($files)) {
return 'php';
}
// add the directory itself as a resource
$container->addResource(new FileResource($dir));
if (is_dir($dir.'/'.$this->getMappingObjectDefaultName())) {
return 'annotation';
}
}
/**
* Loads a configured object manager metadata, query or result cache driver.
*
* @param array $objectManager A configured object manager
* @param ContainerBuilder $container A ContainerBuilder instance
* @param string $cacheName
*
* @throws \InvalidArgumentException in case of unknown driver type
*/
protected function loadObjectManagerCacheDriver(array $objectManager, ContainerBuilder $container, $cacheName)
{
$this->loadCacheDriver($cacheName, $objectManager['name'], $objectManager[$cacheName.'_driver'], $container);
}
/**
* Loads a cache driver.
*
* @param string $cacheName The cache driver name
* @param string $objectManagerName The object manager name
* @param array $cacheDriver The cache driver mapping
* @param ContainerBuilder $container The ContainerBuilder instance
*
* @return string
*
* @throws \InvalidArgumentException
*/
protected function loadCacheDriver($cacheName, $objectManagerName, array $cacheDriver, ContainerBuilder $container)
{
$cacheDriverServiceId = $this->getObjectManagerElementName($objectManagerName.'_'.$cacheName);
switch ($cacheDriver['type']) {
case 'service':
$container->setAlias($cacheDriverServiceId, new Alias($cacheDriver['id'], false));
return $cacheDriverServiceId;
case 'memcache':
$memcacheClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%'.$this->getObjectManagerElementName('cache.memcache.class').'%';
$memcacheInstanceClass = !empty($cacheDriver['instance_class']) ? $cacheDriver['instance_class'] : '%'.$this->getObjectManagerElementName('cache.memcache_instance.class').'%';
$memcacheHost = !empty($cacheDriver['host']) ? $cacheDriver['host'] : '%'.$this->getObjectManagerElementName('cache.memcache_host').'%';
$memcachePort = !empty($cacheDriver['port']) || (isset($cacheDriver['port']) && 0 === $cacheDriver['port']) ? $cacheDriver['port'] : '%'.$this->getObjectManagerElementName('cache.memcache_port').'%';
$cacheDef = new Definition($memcacheClass);
$memcacheInstance = new Definition($memcacheInstanceClass);
$memcacheInstance->addMethodCall('connect', array(
$memcacheHost, $memcachePort,
));
$container->setDefinition($this->getObjectManagerElementName(sprintf('%s_memcache_instance', $objectManagerName)), $memcacheInstance);
$cacheDef->addMethodCall('setMemcache', array(new Reference($this->getObjectManagerElementName(sprintf('%s_memcache_instance', $objectManagerName)))));
break;
case 'memcached':
$memcachedClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%'.$this->getObjectManagerElementName('cache.memcached.class').'%';
$memcachedInstanceClass = !empty($cacheDriver['instance_class']) ? $cacheDriver['instance_class'] : '%'.$this->getObjectManagerElementName('cache.memcached_instance.class').'%';
$memcachedHost = !empty($cacheDriver['host']) ? $cacheDriver['host'] : '%'.$this->getObjectManagerElementName('cache.memcached_host').'%';
$memcachedPort = !empty($cacheDriver['port']) ? $cacheDriver['port'] : '%'.$this->getObjectManagerElementName('cache.memcached_port').'%';
$cacheDef = new Definition($memcachedClass);
$memcachedInstance = new Definition($memcachedInstanceClass);
$memcachedInstance->addMethodCall('addServer', array(
$memcachedHost, $memcachedPort,
));
$container->setDefinition($this->getObjectManagerElementName(sprintf('%s_memcached_instance', $objectManagerName)), $memcachedInstance);
$cacheDef->addMethodCall('setMemcached', array(new Reference($this->getObjectManagerElementName(sprintf('%s_memcached_instance', $objectManagerName)))));
break;
case 'redis':
$redisClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%'.$this->getObjectManagerElementName('cache.redis.class').'%';
$redisInstanceClass = !empty($cacheDriver['instance_class']) ? $cacheDriver['instance_class'] : '%'.$this->getObjectManagerElementName('cache.redis_instance.class').'%';
$redisHost = !empty($cacheDriver['host']) ? $cacheDriver['host'] : '%'.$this->getObjectManagerElementName('cache.redis_host').'%';
$redisPort = !empty($cacheDriver['port']) ? $cacheDriver['port'] : '%'.$this->getObjectManagerElementName('cache.redis_port').'%';
$cacheDef = new Definition($redisClass);
$redisInstance = new Definition($redisInstanceClass);
$redisInstance->addMethodCall('connect', array(
$redisHost, $redisPort,
));
$container->setDefinition($this->getObjectManagerElementName(sprintf('%s_redis_instance', $objectManagerName)), $redisInstance);
$cacheDef->addMethodCall('setRedis', array(new Reference($this->getObjectManagerElementName(sprintf('%s_redis_instance', $objectManagerName)))));
break;
case 'apc':
case 'array':
case 'xcache':
case 'wincache':
case 'zenddata':
$cacheDef = new Definition('%'.$this->getObjectManagerElementName(sprintf('cache.%s.class', $cacheDriver['type'])).'%');
break;
default:
throw new \InvalidArgumentException(sprintf('"%s" is an unrecognized Doctrine cache driver.', $cacheDriver['type']));
}
$cacheDef->setPublic(false);
if (!isset($cacheDriver['namespace'])) {
// generate a unique namespace for the given application
$env = $container->getParameter('kernel.root_dir').$container->getParameter('kernel.environment');
$hash = hash('sha256', $env);
$namespace = 'sf2'.$this->getMappingResourceExtension().'_'.$objectManagerName.'_'.$hash;
$cacheDriver['namespace'] = $namespace;
}
$cacheDef->addMethodCall('setNamespace', array($cacheDriver['namespace']));
$container->setDefinition($cacheDriverServiceId, $cacheDef);
return $cacheDriverServiceId;
}
/**
* Returns a modified version of $managerConfigs.
*
* The manager called $autoMappedManager will map all bundles that are not mapped by other managers.
*
* @return array The modified version of $managerConfigs
*/
protected function fixManagersAutoMappings(array $managerConfigs, array $bundles)
{
if ($autoMappedManager = $this->validateAutoMapping($managerConfigs)) {
foreach (array_keys($bundles) as $bundle) {
foreach ($managerConfigs as $manager) {
if (isset($manager['mappings'][$bundle])) {
continue 2;
}
}
$managerConfigs[$autoMappedManager]['mappings'][$bundle] = array(
'mapping' => true,
'is_bundle' => true,
);
}
$managerConfigs[$autoMappedManager]['auto_mapping'] = false;
}
return $managerConfigs;
}
/**
* Prefixes the relative dependency injection container path with the object manager prefix.
*
* @example $name is 'entity_manager' then the result would be 'doctrine.orm.entity_manager'
*
* @param string $name
*
* @return string
*/
abstract protected function getObjectManagerElementName($name);
/**
* Noun that describes the mapped objects such as Entity or Document.
*
* Will be used for autodetection of persistent objects directory.
*
* @return string
*/
abstract protected function getMappingObjectDefaultName();
/**
* Relative path from the bundle root to the directory where mapping files reside.
*
* @return string
*/
abstract protected function getMappingResourceConfigDirectory();
/**
* Extension used by the mapping files.
*
* @return string
*/
abstract protected function getMappingResourceExtension();
/**
* Search for a manager that is declared as 'auto_mapping' = true.
*
* @return string|null The name of the manager. If no one manager is found, returns null
*
* @throws \LogicException
*/
private function validateAutoMapping(array $managerConfigs)
{
$autoMappedManager = null;
foreach ($managerConfigs as $name => $manager) {
if (!$manager['auto_mapping']) {
continue;
}
if (null !== $autoMappedManager) {
throw new \LogicException(sprintf('You cannot enable "auto_mapping" on more than one manager at the same time (found in "%s" and %s").', $autoMappedManager, $name));
}
$autoMappedManager = $name;
}
return $autoMappedManager;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Registers additional validators.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class DoctrineValidationPass implements CompilerPassInterface
{
private $managerType;
/**
* @param string $managerType
*/
public function __construct($managerType)
{
$this->managerType = $managerType;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$this->updateValidatorMappingFiles($container, 'xml', 'xml');
$this->updateValidatorMappingFiles($container, 'yaml', 'yml');
}
/**
* Gets the validation mapping files for the format and extends them with
* files matching a doctrine search pattern (Resources/config/validation.orm.xml).
*
* @param ContainerBuilder $container
* @param string $mapping
* @param string $extension
*/
private function updateValidatorMappingFiles(ContainerBuilder $container, $mapping, $extension)
{
if (!$container->hasParameter('validator.mapping.loader.'.$mapping.'_files_loader.mapping_files')) {
return;
}
$files = $container->getParameter('validator.mapping.loader.'.$mapping.'_files_loader.mapping_files');
$validationPath = 'Resources/config/validation.'.$this->managerType.'.'.$extension;
foreach ($container->getParameter('kernel.bundles') as $bundle) {
$reflection = new \ReflectionClass($bundle);
if (is_file($file = \dirname($reflection->getFileName()).'/'.$validationPath)) {
$files[] = $file;
$container->addResource(new FileResource($file));
}
}
$container->setParameter('validator.mapping.loader.'.$mapping.'_files_loader.mapping_files', $files);
}
}

View File

@@ -0,0 +1,161 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
/**
* Registers event listeners and subscribers to the available doctrine connections.
*
* @author Jeremy Mikola <jmikola@gmail.com>
* @author Alexander <iam.asm89@gmail.com>
* @author David Maicher <mail@dmaicher.de>
*/
class RegisterEventListenersAndSubscribersPass implements CompilerPassInterface
{
private $connections;
private $eventManagers;
private $managerTemplate;
private $tagPrefix;
/**
* @param string $connections Parameter ID for connections
* @param string $managerTemplate sprintf() template for generating the event
* manager's service ID for a connection name
* @param string $tagPrefix Tag prefix for listeners and subscribers
*/
public function __construct($connections, $managerTemplate, $tagPrefix)
{
$this->connections = $connections;
$this->managerTemplate = $managerTemplate;
$this->tagPrefix = $tagPrefix;
}
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasParameter($this->connections)) {
return;
}
$this->connections = $container->getParameter($this->connections);
$this->addTaggedSubscribers($container);
$this->addTaggedListeners($container);
}
private function addTaggedSubscribers(ContainerBuilder $container)
{
$subscriberTag = $this->tagPrefix.'.event_subscriber';
$taggedSubscribers = $this->findAndSortTags($subscriberTag, $container);
foreach ($taggedSubscribers as $taggedSubscriber) {
$id = $taggedSubscriber[0];
$taggedSubscriberDef = $container->getDefinition($id);
if ($taggedSubscriberDef->isAbstract()) {
throw new InvalidArgumentException(sprintf('The abstract service "%s" cannot be tagged as a doctrine event subscriber.', $id));
}
$tag = $taggedSubscriber[1];
$connections = isset($tag['connection']) ? array($tag['connection']) : array_keys($this->connections);
foreach ($connections as $con) {
if (!isset($this->connections[$con])) {
throw new RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $id, implode(', ', array_keys($this->connections))));
}
$this->getEventManagerDef($container, $con)->addMethodCall('addEventSubscriber', array(new Reference($id)));
}
}
}
private function addTaggedListeners(ContainerBuilder $container)
{
$listenerTag = $this->tagPrefix.'.event_listener';
$taggedListeners = $this->findAndSortTags($listenerTag, $container);
foreach ($taggedListeners as $taggedListener) {
$id = $taggedListener[0];
$taggedListenerDef = $container->getDefinition($taggedListener[0]);
if ($taggedListenerDef->isAbstract()) {
throw new InvalidArgumentException(sprintf('The abstract service "%s" cannot be tagged as a doctrine event listener.', $id));
}
$tag = $taggedListener[1];
if (!isset($tag['event'])) {
throw new InvalidArgumentException(sprintf('Doctrine event listener "%s" must specify the "event" attribute.', $id));
}
$connections = isset($tag['connection']) ? array($tag['connection']) : array_keys($this->connections);
foreach ($connections as $con) {
if (!isset($this->connections[$con])) {
throw new RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $id, implode(', ', array_keys($this->connections))));
}
if ($lazy = !empty($tag['lazy'])) {
$taggedListenerDef->setPublic(true);
}
// we add one call per event per service so we have the correct order
$this->getEventManagerDef($container, $con)->addMethodCall('addEventListener', array(array($tag['event']), $lazy ? $id : new Reference($id)));
}
}
}
private function getEventManagerDef(ContainerBuilder $container, $name)
{
if (!isset($this->eventManagers[$name])) {
$this->eventManagers[$name] = $container->getDefinition(sprintf($this->managerTemplate, $name));
}
return $this->eventManagers[$name];
}
/**
* Finds and orders all service tags with the given name by their priority.
*
* The order of additions must be respected for services having the same priority,
* and knowing that the \SplPriorityQueue class does not respect the FIFO method,
* we should not use this class.
*
* @see https://bugs.php.net/bug.php?id=53710
* @see https://bugs.php.net/bug.php?id=60926
*
* @param string $tagName
* @param ContainerBuilder $container
*
* @return array
*/
private function findAndSortTags($tagName, ContainerBuilder $container)
{
$sortedTags = array();
foreach ($container->findTaggedServiceIds($tagName) as $serviceId => $tags) {
foreach ($tags as $attributes) {
$priority = isset($attributes['priority']) ? $attributes['priority'] : 0;
$sortedTags[$priority][] = array($serviceId, $attributes);
}
}
if ($sortedTags) {
krsort($sortedTags);
$sortedTags = \call_user_func_array('array_merge', $sortedTags);
}
return $sortedTags;
}
}

View File

@@ -0,0 +1,241 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
use Symfony\Component\DependencyInjection\Reference;
/**
* Base class for the doctrine bundles to provide a compiler pass class that
* helps to register doctrine mappings.
*
* The compiler pass is meant to register the mappings with the metadata
* chain driver corresponding to one of the object managers.
*
* For concrete implementations that are easy to use, see the
* RegisterXyMappingsPass classes in the DoctrineBundle resp.
* DoctrineMongodbBundle, DoctrineCouchdbBundle and DoctrinePhpcrBundle.
*
* @author David Buchmann <david@liip.ch>
*/
abstract class RegisterMappingsPass implements CompilerPassInterface
{
/**
* DI object for the driver to use, either a service definition for a
* private service or a reference for a public service.
*
* @var Definition|Reference
*/
protected $driver;
/**
* List of namespaces handled by the driver.
*
* @var string[]
*/
protected $namespaces;
/**
* List of potential container parameters that hold the object manager name
* to register the mappings with the correct metadata driver, for example
* array('acme.manager', 'doctrine.default_entity_manager').
*
* @var string[]
*/
protected $managerParameters;
/**
* Naming pattern of the metadata chain driver service ids, for example
* 'doctrine.orm.%s_metadata_driver'.
*
* @var string
*/
protected $driverPattern;
/**
* A name for a parameter in the container. If set, this compiler pass will
* only do anything if the parameter is present. (But regardless of the
* value of that parameter.
*
* @var string|false
*/
protected $enabledParameter;
/**
* Naming pattern for the configuration service id, for example
* 'doctrine.orm.%s_configuration'.
*
* @var string
*/
private $configurationPattern;
/**
* Method name to call on the configuration service. This depends on the
* Doctrine implementation. For example addEntityNamespace.
*
* @var string
*/
private $registerAliasMethodName;
/**
* Map of alias to namespace.
*
* @var string[]
*/
private $aliasMap;
/**
* The $managerParameters is an ordered list of container parameters that could provide the
* name of the manager to register these namespaces and alias on. The first non-empty name
* is used, the others skipped.
*
* The $aliasMap parameter can be used to define bundle namespace shortcuts like the
* DoctrineBundle provides automatically for objects in the default Entity/Document folder.
*
* @param Definition|Reference $driver Driver DI definition or reference
* @param string[] $namespaces List of namespaces handled by $driver
* @param string[] $managerParameters list of container parameters that could
* hold the manager name
* @param string $driverPattern Pattern for the metadata driver service name
* @param string|false $enabledParameter Service container parameter that must be
* present to enable the mapping. Set to false
* to not do any check, optional.
* @param string $configurationPattern Pattern for the Configuration service name
* @param string $registerAliasMethodName Name of Configuration class method to
* register alias
* @param string[] $aliasMap Map of alias to namespace
*/
public function __construct($driver, array $namespaces, array $managerParameters, $driverPattern, $enabledParameter = false, $configurationPattern = '', $registerAliasMethodName = '', array $aliasMap = array())
{
$this->driver = $driver;
$this->namespaces = $namespaces;
$this->managerParameters = $managerParameters;
$this->driverPattern = $driverPattern;
$this->enabledParameter = $enabledParameter;
if (\count($aliasMap) && (!$configurationPattern || !$registerAliasMethodName)) {
throw new \InvalidArgumentException('configurationPattern and registerAliasMethodName are required to register namespace alias');
}
$this->configurationPattern = $configurationPattern;
$this->registerAliasMethodName = $registerAliasMethodName;
$this->aliasMap = $aliasMap;
}
/**
* Register mappings and alias with the metadata drivers.
*/
public function process(ContainerBuilder $container)
{
if (!$this->enabled($container)) {
return;
}
$mappingDriverDef = $this->getDriver($container);
$chainDriverDefService = $this->getChainDriverServiceName($container);
// Definition for a Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain
$chainDriverDef = $container->getDefinition($chainDriverDefService);
foreach ($this->namespaces as $namespace) {
$chainDriverDef->addMethodCall('addDriver', array($mappingDriverDef, $namespace));
}
if (!\count($this->aliasMap)) {
return;
}
$configurationServiceName = $this->getConfigurationServiceName($container);
// Definition of the Doctrine\...\Configuration class specific to the Doctrine flavour.
$configurationServiceDefinition = $container->getDefinition($configurationServiceName);
foreach ($this->aliasMap as $alias => $namespace) {
$configurationServiceDefinition->addMethodCall($this->registerAliasMethodName, array($alias, $namespace));
}
}
/**
* Get the service name of the metadata chain driver that the mappings
* should be registered with.
*
* @return string The name of the chain driver service
*
* @throws ParameterNotFoundException if non of the managerParameters has a
* non-empty value
*/
protected function getChainDriverServiceName(ContainerBuilder $container)
{
return sprintf($this->driverPattern, $this->getManagerName($container));
}
/**
* Create the service definition for the metadata driver.
*
* @param ContainerBuilder $container Passed on in case an extending class
* needs access to the container
*
* @return Definition|Reference the metadata driver to add to all chain drivers
*/
protected function getDriver(ContainerBuilder $container)
{
return $this->driver;
}
/**
* Get the service name from the pattern and the configured manager name.
*
* @return string a service definition name
*
* @throws ParameterNotFoundException if none of the managerParameters has a
* non-empty value
*/
private function getConfigurationServiceName(ContainerBuilder $container)
{
return sprintf($this->configurationPattern, $this->getManagerName($container));
}
/**
* Determine the manager name.
*
* The default implementation loops over the managerParameters and returns
* the first non-empty parameter.
*
* @return string The name of the active manager
*
* @throws ParameterNotFoundException if none of the managerParameters is found in the container
*/
private function getManagerName(ContainerBuilder $container)
{
foreach ($this->managerParameters as $param) {
if ($container->hasParameter($param)) {
$name = $container->getParameter($param);
if ($name) {
return $name;
}
}
}
throw new ParameterNotFoundException('Could not determine the Doctrine manager. Either Doctrine is not configured or a bundle is misconfigured.');
}
/**
* Determine whether this mapping should be activated or not. This allows
* to take this decision with the container builder available.
*
* This default implementation checks if the class has the enabledParameter
* configured and if so if that parameter is present in the container.
*
* @return bool whether this compiler pass really should register the mappings
*/
protected function enabled(ContainerBuilder $container)
{
return !$this->enabledParameter || $container->hasParameter($this->enabledParameter);
}
}

View File

@@ -0,0 +1,61 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Doctrine\DependencyInjection\Security\UserProvider;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\UserProviderFactoryInterface;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
/**
* EntityFactory creates services for Doctrine user provider.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Christophe Coevoet <stof@notk.org>
*/
class EntityFactory implements UserProviderFactoryInterface
{
private $key;
private $providerId;
public function __construct($key, $providerId)
{
$this->key = $key;
$this->providerId = $providerId;
}
public function create(ContainerBuilder $container, $id, $config)
{
$container
->setDefinition($id, new DefinitionDecorator($this->providerId))
->addArgument($config['class'])
->addArgument($config['property'])
->addArgument($config['manager_name'])
;
}
public function getKey()
{
return $this->key;
}
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('class')->isRequired()->cannotBeEmpty()->end()
->scalarNode('property')->defaultNull()->end()
->scalarNode('manager_name')->defaultNull()->end()
->end()
;
}
}