vendor/symfony/src/Symfony/Bundle/DoctrineBundle/DependencyInjection/DoctrineExtension.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony package.
       
     5  *
       
     6  * (c) Fabien Potencier <fabien@symfony.com>
       
     7  *
       
     8  * For the full copyright and license information, please view the LICENSE
       
     9  * file that was distributed with this source code.
       
    10  */
       
    11 
       
    12 namespace Symfony\Bundle\DoctrineBundle\DependencyInjection;
       
    13 
       
    14 use Symfony\Component\DependencyInjection\Alias;
       
    15 use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
       
    16 use Symfony\Component\DependencyInjection\ContainerBuilder;
       
    17 use Symfony\Component\DependencyInjection\Definition;
       
    18 use Symfony\Component\DependencyInjection\DefinitionDecorator;
       
    19 use Symfony\Component\DependencyInjection\Reference;
       
    20 use Symfony\Bundle\DoctrineAbstractBundle\DependencyInjection\AbstractDoctrineExtension;
       
    21 use Symfony\Component\Config\FileLocator;
       
    22 
       
    23 /**
       
    24  * DoctrineExtension is an extension for the Doctrine DBAL and ORM library.
       
    25  *
       
    26  * @author Jonathan H. Wage <jonwage@gmail.com>
       
    27  * @author Fabien Potencier <fabien@symfony.com>
       
    28  * @author Benjamin Eberlei <kontakt@beberlei.de>
       
    29  */
       
    30 class DoctrineExtension extends AbstractDoctrineExtension
       
    31 {
       
    32     public function load(array $configs, ContainerBuilder $container)
       
    33     {
       
    34         $configuration = new Configuration($container->getParameter('kernel.debug'));
       
    35         $config = $this->processConfiguration($configuration, $configs);
       
    36 
       
    37         if (!empty($config['dbal'])) {
       
    38             $this->dbalLoad($config['dbal'], $container);
       
    39         }
       
    40 
       
    41         if (!empty($config['orm'])) {
       
    42             $this->ormLoad($config['orm'], $container);
       
    43         }
       
    44     }
       
    45 
       
    46     /**
       
    47      * Loads the DBAL configuration.
       
    48      *
       
    49      * Usage example:
       
    50      *
       
    51      *      <doctrine:dbal id="myconn" dbname="sfweb" user="root" />
       
    52      *
       
    53      * @param array            $config    An array of configuration settings
       
    54      * @param ContainerBuilder $container A ContainerBuilder instance
       
    55      */
       
    56     protected function dbalLoad(array $config, ContainerBuilder $container)
       
    57     {
       
    58         $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
       
    59         $loader->load('dbal.xml');
       
    60 
       
    61         if (empty($config['default_connection'])) {
       
    62             $keys = array_keys($config['connections']);
       
    63             $config['default_connection'] = reset($keys);
       
    64         }
       
    65         $this->defaultConnection = $config['default_connection'];
       
    66 
       
    67         $container->setAlias('database_connection', sprintf('doctrine.dbal.%s_connection', $this->defaultConnection));
       
    68         $container->setAlias('doctrine.dbal.event_manager', new Alias(sprintf('doctrine.dbal.%s_connection.event_manager', $this->defaultConnection), false));
       
    69 
       
    70         $container->setParameter('doctrine.dbal.connection_factory.types', $config['types']);
       
    71 
       
    72         $connections = array();
       
    73         foreach (array_keys($config['connections']) as $name) {
       
    74             $connections[$name] = sprintf('doctrine.dbal.%s_connection', $name);
       
    75         }
       
    76         $container->setParameter('doctrine.connections', $connections);
       
    77         $container->setParameter('doctrine.default_connection', $this->defaultConnection);
       
    78 
       
    79         foreach ($config['connections'] as $name => $connection) {
       
    80             $this->loadDbalConnection($name, $connection, $container);
       
    81         }
       
    82     }
       
    83 
       
    84     /**
       
    85      * Loads a configured DBAL connection.
       
    86      *
       
    87      * @param string           $name       The name of the connection
       
    88      * @param array            $connection A dbal connection configuration.
       
    89      * @param ContainerBuilder $container  A ContainerBuilder instance
       
    90      */
       
    91     protected function loadDbalConnection($name, array $connection, ContainerBuilder $container)
       
    92     {
       
    93         // configuration
       
    94         $configuration = $container->setDefinition(sprintf('doctrine.dbal.%s_connection.configuration', $name), new DefinitionDecorator('doctrine.dbal.connection.configuration'));
       
    95         if (isset($connection['logging']) && $connection['logging']) {
       
    96             $configuration->addMethodCall('setSQLLogger', array(new Reference('doctrine.dbal.logger')));
       
    97             unset ($connection['logging']);
       
    98         }
       
    99 
       
   100         // event manager
       
   101         $def = $container->setDefinition(sprintf('doctrine.dbal.%s_connection.event_manager', $name), new DefinitionDecorator('doctrine.dbal.connection.event_manager'));
       
   102 
       
   103         // connection
       
   104         if (isset($connection['charset'])) {
       
   105             if ((isset($connection['driver']) && stripos($connection['driver'], 'mysql') !== false) ||
       
   106                  (isset($connection['driver_class']) && stripos($connection['driver_class'], 'mysql') !== false)) {
       
   107                 $mysqlSessionInit = new Definition('%doctrine.dbal.events.mysql_session_init.class%');
       
   108                 $mysqlSessionInit->setArguments(array($connection['charset']));
       
   109                 $mysqlSessionInit->setPublic(false);
       
   110                 $mysqlSessionInit->addTag('doctrine.event_subscriber', array('connection' => $name));
       
   111 
       
   112                 $container->setDefinition(
       
   113                     sprintf('doctrine.dbal.%s_connection.events.mysqlsessioninit', $name),
       
   114                     $mysqlSessionInit
       
   115                 );
       
   116                 unset($connection['charset']);
       
   117             }
       
   118         }
       
   119 
       
   120         $options = $this->getConnectionOptions($connection);
       
   121 
       
   122         $container
       
   123             ->setDefinition(sprintf('doctrine.dbal.%s_connection', $name), new DefinitionDecorator('doctrine.dbal.connection'))
       
   124             ->setArguments(array(
       
   125                 $options,
       
   126                 new Reference(sprintf('doctrine.dbal.%s_connection.configuration', $name)),
       
   127                 new Reference(sprintf('doctrine.dbal.%s_connection.event_manager', $name)),
       
   128                 $connection['mapping_types'],
       
   129             ))
       
   130         ;
       
   131     }
       
   132 
       
   133     protected function getConnectionOptions($connection)
       
   134     {
       
   135         $options = $connection;
       
   136 
       
   137         if (isset($options['platform_service'])) {
       
   138             $options['platform'] = new Reference($options['platform_service']);
       
   139             unset($options['platform_service']);
       
   140         }
       
   141         unset($options['mapping_types']);
       
   142 
       
   143         foreach (array(
       
   144             'options' => 'driverOptions',
       
   145             'driver_class' => 'driverClass',
       
   146             'wrapper_class' => 'wrapperClass',
       
   147         ) as $old => $new) {
       
   148             if (isset($options[$old])) {
       
   149                 $options[$new] = $options[$old];
       
   150                 unset($options[$old]);
       
   151             }
       
   152         }
       
   153 
       
   154         return $options;
       
   155     }
       
   156 
       
   157     /**
       
   158      * Loads the Doctrine ORM configuration.
       
   159      *
       
   160      * Usage example:
       
   161      *
       
   162      *     <doctrine:orm id="mydm" connection="myconn" />
       
   163      *
       
   164      * @param array            $config    An array of configuration settings
       
   165      * @param ContainerBuilder $container A ContainerBuilder instance
       
   166      */
       
   167     protected function ormLoad(array $config, ContainerBuilder $container)
       
   168     {
       
   169         $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
       
   170         $loader->load('orm.xml');
       
   171 
       
   172         $this->entityManagers = array();
       
   173         foreach (array_keys($config['entity_managers']) as $name) {
       
   174             $this->entityManagers[$name] = sprintf('doctrine.orm.%s_entity_manager', $name);
       
   175         }
       
   176         $container->setParameter('doctrine.entity_managers', $this->entityManagers);
       
   177 
       
   178         if (empty($config['default_entity_manager'])) {
       
   179             $tmp = array_keys($this->entityManagers);
       
   180             $config['default_entity_manager'] = reset($tmp);
       
   181         }
       
   182         $container->setParameter('doctrine.default_entity_manager', $config['default_entity_manager']);
       
   183 
       
   184         $options = array('auto_generate_proxy_classes', 'proxy_dir', 'proxy_namespace');
       
   185         foreach ($options as $key) {
       
   186             $container->setParameter('doctrine.orm.'.$key, $config[$key]);
       
   187         }
       
   188 
       
   189         $container->setAlias('doctrine.orm.entity_manager', sprintf('doctrine.orm.%s_entity_manager', $config['default_entity_manager']));
       
   190 
       
   191         foreach ($config['entity_managers'] as $name => $entityManager) {
       
   192             $entityManager['name'] = $name;
       
   193             $this->loadOrmEntityManager($entityManager, $container);
       
   194         }
       
   195     }
       
   196 
       
   197     /**
       
   198      * Loads a configured ORM entity manager.
       
   199      *
       
   200      * @param array $entityManager A configured ORM entity manager.
       
   201      * @param ContainerBuilder $container A ContainerBuilder instance
       
   202      */
       
   203     protected function loadOrmEntityManager(array $entityManager, ContainerBuilder $container)
       
   204     {
       
   205         if ($entityManager['auto_mapping'] && count($this->entityManagers) > 1) {
       
   206             throw new \LogicException('You cannot enable "auto_mapping" when several entity managers are defined.');
       
   207         }
       
   208 
       
   209         $ormConfigDef = $container->setDefinition(sprintf('doctrine.orm.%s_configuration', $entityManager['name']), new DefinitionDecorator('doctrine.orm.configuration'));
       
   210 
       
   211         $this->loadOrmEntityManagerMappingInformation($entityManager, $ormConfigDef, $container);
       
   212         $this->loadOrmCacheDrivers($entityManager, $container);
       
   213 
       
   214         $methods = array(
       
   215             'setMetadataCacheImpl'        => new Reference(sprintf('doctrine.orm.%s_metadata_cache', $entityManager['name'])),
       
   216             'setQueryCacheImpl'           => new Reference(sprintf('doctrine.orm.%s_query_cache', $entityManager['name'])),
       
   217             'setResultCacheImpl'          => new Reference(sprintf('doctrine.orm.%s_result_cache', $entityManager['name'])),
       
   218             'setMetadataDriverImpl'       => new Reference('doctrine.orm.'.$entityManager['name'].'_metadata_driver'),
       
   219             'setProxyDir'                 => '%doctrine.orm.proxy_dir%',
       
   220             'setProxyNamespace'           => '%doctrine.orm.proxy_namespace%',
       
   221             'setAutoGenerateProxyClasses' => '%doctrine.orm.auto_generate_proxy_classes%',
       
   222             'setClassMetadataFactoryName' => $entityManager['class_metadata_factory_name'],
       
   223         );
       
   224         foreach ($methods as $method => $arg) {
       
   225             $ormConfigDef->addMethodCall($method, array($arg));
       
   226         }
       
   227 
       
   228         foreach ($entityManager['hydrators'] as $name => $class) {
       
   229             $ormConfigDef->addMethodCall('addCustomHydrationMode', array($name, $class));
       
   230         }
       
   231 
       
   232         if (!empty($entityManager['dql'])) {
       
   233             foreach ($entityManager['dql']['string_functions'] as $name => $function) {
       
   234                 $ormConfigDef->addMethodCall('addCustomStringFunction', array($name, $function));
       
   235             }
       
   236             foreach ($entityManager['dql']['numeric_functions'] as $name => $function) {
       
   237                 $ormConfigDef->addMethodCall('addCustomNumericFunction', array($name, $function));
       
   238             }
       
   239             foreach ($entityManager['dql']['datetime_functions'] as $name => $function) {
       
   240                 $ormConfigDef->addMethodCall('addCustomDatetimeFunction', array($name, $function));
       
   241             }
       
   242         }
       
   243 
       
   244         if (!isset($entityManager['connection'])) {
       
   245             $entityManager['connection'] = $this->defaultConnection;
       
   246         }
       
   247 
       
   248         $container
       
   249             ->setDefinition(sprintf('doctrine.orm.%s_entity_manager', $entityManager['name']), new DefinitionDecorator('doctrine.orm.entity_manager.abstract'))
       
   250             ->setArguments(array(
       
   251                 new Reference(sprintf('doctrine.dbal.%s_connection', $entityManager['connection'])),
       
   252                 new Reference(sprintf('doctrine.orm.%s_configuration', $entityManager['name']))
       
   253             ))
       
   254         ;
       
   255 
       
   256         $container->setAlias(
       
   257             sprintf('doctrine.orm.%s_entity_manager.event_manager', $entityManager['name']),
       
   258             new Alias(sprintf('doctrine.dbal.%s_connection.event_manager', $entityManager['connection']), false)
       
   259         );
       
   260     }
       
   261 
       
   262     /**
       
   263      * Loads an ORM entity managers bundle mapping information.
       
   264      *
       
   265      * There are two distinct configuration possibilities for mapping information:
       
   266      *
       
   267      * 1. Specify a bundle and optionally details where the entity and mapping information reside.
       
   268      * 2. Specify an arbitrary mapping location.
       
   269      *
       
   270      * @example
       
   271      *
       
   272      *  doctrine.orm:
       
   273      *     mappings:
       
   274      *         MyBundle1: ~
       
   275      *         MyBundle2: yml
       
   276      *         MyBundle3: { type: annotation, dir: Entities/ }
       
   277      *         MyBundle4: { type: xml, dir: Resources/config/doctrine/mapping }
       
   278      *         MyBundle5:
       
   279      *             type: yml
       
   280      *             dir: [bundle-mappings1/, bundle-mappings2/]
       
   281      *             alias: BundleAlias
       
   282      *         arbitrary_key:
       
   283      *             type: xml
       
   284      *             dir: %kernel.dir%/../src/vendor/DoctrineExtensions/lib/DoctrineExtensions/Entities
       
   285      *             prefix: DoctrineExtensions\Entities\
       
   286      *             alias: DExt
       
   287      *
       
   288      * In the case of bundles everything is really optional (which leads to autodetection for this bundle) but
       
   289      * in the mappings key everything except alias is a required argument.
       
   290      *
       
   291      * @param array $entityManager A configured ORM entity manager.
       
   292      * @param ContainerBuilder $container A ContainerBuilder instance
       
   293      */
       
   294     protected function loadOrmEntityManagerMappingInformation(array $entityManager, Definition $ormConfigDef, ContainerBuilder $container)
       
   295     {
       
   296         // reset state of drivers and alias map. They are only used by this methods and children.
       
   297         $this->drivers = array();
       
   298         $this->aliasMap = array();
       
   299 
       
   300         $this->loadMappingInformation($entityManager, $container);
       
   301         $this->registerMappingDrivers($entityManager, $container);
       
   302 
       
   303         $ormConfigDef->addMethodCall('setEntityNamespaces', array($this->aliasMap));
       
   304     }
       
   305 
       
   306     protected function getObjectManagerElementName($name)
       
   307     {
       
   308         return 'doctrine.orm.'.$name;
       
   309     }
       
   310 
       
   311     protected function getMappingObjectDefaultName()
       
   312     {
       
   313         return 'Entity';
       
   314     }
       
   315 
       
   316     protected function getMappingResourceConfigDirectory()
       
   317     {
       
   318         return 'Resources/config/doctrine';
       
   319     }
       
   320 
       
   321     protected function getMappingResourceExtension()
       
   322     {
       
   323         return 'orm';
       
   324     }
       
   325 
       
   326     /**
       
   327      * Loads a configured entity managers cache drivers.
       
   328      *
       
   329      * @param array            $entityManager A configured ORM entity manager.
       
   330      * @param ContainerBuilder $container     A ContainerBuilder instance
       
   331      */
       
   332     protected function loadOrmCacheDrivers(array $entityManager, ContainerBuilder $container)
       
   333     {
       
   334         $this->loadOrmEntityManagerCacheDriver($entityManager, $container, 'metadata_cache');
       
   335         $this->loadOrmEntityManagerCacheDriver($entityManager, $container, 'result_cache');
       
   336         $this->loadOrmEntityManagerCacheDriver($entityManager, $container, 'query_cache');
       
   337     }
       
   338 
       
   339     /**
       
   340      * Loads a configured entity managers metadata, query or result cache driver.
       
   341      *
       
   342      * @param array            $entityManager A configured ORM entity manager.
       
   343      * @param ContainerBuilder $container A ContainerBuilder instance
       
   344      * @param string           $cacheName
       
   345      */
       
   346     protected function loadOrmEntityManagerCacheDriver(array $entityManager, ContainerBuilder $container, $cacheName)
       
   347     {
       
   348         $cacheDriverService = sprintf('doctrine.orm.%s_%s', $entityManager['name'], $cacheName);
       
   349 
       
   350         $driver = $cacheName."_driver";
       
   351         $cacheDef = $this->getEntityManagerCacheDefinition($entityManager, $entityManager[$driver], $container);
       
   352         $container->setDefinition($cacheDriverService, $cacheDef);
       
   353     }
       
   354 
       
   355     /**
       
   356      * Gets an entity manager cache driver definition for metadata, query and result caches.
       
   357      *
       
   358      * @param array            $entityManager The array configuring an entity manager.
       
   359      * @param array            $cacheDriver The cache driver configuration.
       
   360      * @param ContainerBuilder $container
       
   361      * @return Definition $cacheDef
       
   362      */
       
   363     protected function getEntityManagerCacheDefinition(array $entityManager, $cacheDriver, ContainerBuilder $container)
       
   364     {
       
   365         switch ($cacheDriver['type']) {
       
   366             case 'memcache':
       
   367                 $memcacheClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%doctrine.orm.cache.memcache.class%';
       
   368                 $memcacheInstanceClass = !empty($cacheDriver['instance_class']) ? $cacheDriver['instance_class'] : '%doctrine.orm.cache.memcache_instance.class%';
       
   369                 $memcacheHost = !empty($cacheDriver['host']) ? $cacheDriver['host'] : '%doctrine.orm.cache.memcache_host%';
       
   370                 $memcachePort = !empty($cacheDriver['port']) ? $cacheDriver['port'] : '%doctrine.orm.cache.memcache_port%';
       
   371                 $cacheDef = new Definition($memcacheClass);
       
   372                 $memcacheInstance = new Definition($memcacheInstanceClass);
       
   373                 $memcacheInstance->addMethodCall('connect', array(
       
   374                     $memcacheHost, $memcachePort
       
   375                 ));
       
   376                 $container->setDefinition(sprintf('doctrine.orm.%s_memcache_instance', $entityManager['name']), $memcacheInstance);
       
   377                 $cacheDef->addMethodCall('setMemcache', array(new Reference(sprintf('doctrine.orm.%s_memcache_instance', $entityManager['name']))));
       
   378                 break;
       
   379             case 'apc':
       
   380             case 'array':
       
   381             case 'xcache':
       
   382                 $cacheDef = new Definition('%'.sprintf('doctrine.orm.cache.%s.class', $cacheDriver['type']).'%');
       
   383                 break;
       
   384             default:
       
   385                 throw new \InvalidArgumentException(sprintf('"%s" is an unrecognized Doctrine cache driver.', $cacheDriver['type']));
       
   386         }
       
   387 
       
   388         $cacheDef->setPublic(false);
       
   389         // generate a unique namespace for the given application
       
   390         $namespace = 'sf2orm_'.$entityManager['name'].'_'.md5($container->getParameter('kernel.root_dir').$container->getParameter('kernel.environment'));
       
   391         $cacheDef->addMethodCall('setNamespace', array($namespace));
       
   392 
       
   393         return $cacheDef;
       
   394     }
       
   395 
       
   396     /**
       
   397      * Returns the base path for the XSD files.
       
   398      *
       
   399      * @return string The XSD base path
       
   400      */
       
   401     public function getXsdValidationBasePath()
       
   402     {
       
   403         return __DIR__.'/../Resources/config/schema';
       
   404     }
       
   405 
       
   406     /**
       
   407      * Returns the namespace to be used for this extension (XML namespace).
       
   408      *
       
   409      * @return string The XML namespace
       
   410      */
       
   411     public function getNamespace()
       
   412     {
       
   413         return 'http://symfony.com/schema/dic/doctrine';
       
   414     }
       
   415 }