"Fossies" - the Fresh Open Source Software Archive

Member "Symfony/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php" (30 Mar 2020, 21646 Bytes) of package /linux/www/Symfony_Standard_Vendors_3.4.39.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AbstractDoctrineExtension.php" see the Fossies "Dox" file reference documentation.

    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\Bridge\Doctrine\DependencyInjection;
   13 
   14 use Symfony\Component\DependencyInjection\Alias;
   15 use Symfony\Component\DependencyInjection\ContainerBuilder;
   16 use Symfony\Component\DependencyInjection\Definition;
   17 use Symfony\Component\DependencyInjection\Reference;
   18 use Symfony\Component\HttpKernel\DependencyInjection\Extension;
   19 
   20 /**
   21  * This abstract classes groups common code that Doctrine Object Manager extensions (ORM, MongoDB, CouchDB) need.
   22  *
   23  * @author Benjamin Eberlei <kontakt@beberlei.de>
   24  */
   25 abstract class AbstractDoctrineExtension extends Extension
   26 {
   27     /**
   28      * Used inside metadata driver method to simplify aggregation of data.
   29      */
   30     protected $aliasMap = [];
   31 
   32     /**
   33      * Used inside metadata driver method to simplify aggregation of data.
   34      */
   35     protected $drivers = [];
   36 
   37     /**
   38      * @param array            $objectManager A configured object manager
   39      * @param ContainerBuilder $container     A ContainerBuilder instance
   40      *
   41      * @throws \InvalidArgumentException
   42      */
   43     protected function loadMappingInformation(array $objectManager, ContainerBuilder $container)
   44     {
   45         if ($objectManager['auto_mapping']) {
   46             // automatically register bundle mappings
   47             foreach (array_keys($container->getParameter('kernel.bundles')) as $bundle) {
   48                 if (!isset($objectManager['mappings'][$bundle])) {
   49                     $objectManager['mappings'][$bundle] = [
   50                         'mapping' => true,
   51                         'is_bundle' => true,
   52                     ];
   53                 }
   54             }
   55         }
   56 
   57         foreach ($objectManager['mappings'] as $mappingName => $mappingConfig) {
   58             if (null !== $mappingConfig && false === $mappingConfig['mapping']) {
   59                 continue;
   60             }
   61 
   62             $mappingConfig = array_replace([
   63                 'dir' => false,
   64                 'type' => false,
   65                 'prefix' => false,
   66             ], (array) $mappingConfig);
   67 
   68             $mappingConfig['dir'] = $container->getParameterBag()->resolveValue($mappingConfig['dir']);
   69             // a bundle configuration is detected by realizing that the specified dir is not absolute and existing
   70             if (!isset($mappingConfig['is_bundle'])) {
   71                 $mappingConfig['is_bundle'] = !is_dir($mappingConfig['dir']);
   72             }
   73 
   74             if ($mappingConfig['is_bundle']) {
   75                 $bundle = null;
   76                 foreach ($container->getParameter('kernel.bundles') as $name => $class) {
   77                     if ($mappingName === $name) {
   78                         $bundle = new \ReflectionClass($class);
   79 
   80                         break;
   81                     }
   82                 }
   83 
   84                 if (null === $bundle) {
   85                     throw new \InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled.', $mappingName));
   86                 }
   87 
   88                 $mappingConfig = $this->getMappingDriverBundleConfigDefaults($mappingConfig, $bundle, $container);
   89                 if (!$mappingConfig) {
   90                     continue;
   91                 }
   92             }
   93 
   94             $this->assertValidMappingConfiguration($mappingConfig, $objectManager['name']);
   95             $this->setMappingDriverConfig($mappingConfig, $mappingName);
   96             $this->setMappingDriverAlias($mappingConfig, $mappingName);
   97         }
   98     }
   99 
  100     /**
  101      * Register the alias for this mapping driver.
  102      *
  103      * Aliases can be used in the Query languages of all the Doctrine object managers to simplify writing tasks.
  104      *
  105      * @param array  $mappingConfig
  106      * @param string $mappingName
  107      */
  108     protected function setMappingDriverAlias($mappingConfig, $mappingName)
  109     {
  110         if (isset($mappingConfig['alias'])) {
  111             $this->aliasMap[$mappingConfig['alias']] = $mappingConfig['prefix'];
  112         } else {
  113             $this->aliasMap[$mappingName] = $mappingConfig['prefix'];
  114         }
  115     }
  116 
  117     /**
  118      * Register the mapping driver configuration for later use with the object managers metadata driver chain.
  119      *
  120      * @param string $mappingName
  121      *
  122      * @throws \InvalidArgumentException
  123      */
  124     protected function setMappingDriverConfig(array $mappingConfig, $mappingName)
  125     {
  126         $mappingDirectory = $mappingConfig['dir'];
  127         if (!is_dir($mappingDirectory)) {
  128             throw new \InvalidArgumentException(sprintf('Invalid Doctrine mapping path given. Cannot load Doctrine mapping/bundle named "%s".', $mappingName));
  129         }
  130 
  131         $this->drivers[$mappingConfig['type']][$mappingConfig['prefix']] = realpath($mappingDirectory) ?: $mappingDirectory;
  132     }
  133 
  134     /**
  135      * If this is a bundle controlled mapping all the missing information can be autodetected by this method.
  136      *
  137      * Returns false when autodetection failed, an array of the completed information otherwise.
  138      *
  139      * @return array|false
  140      */
  141     protected function getMappingDriverBundleConfigDefaults(array $bundleConfig, \ReflectionClass $bundle, ContainerBuilder $container)
  142     {
  143         $bundleDir = \dirname($bundle->getFileName());
  144 
  145         if (!$bundleConfig['type']) {
  146             $bundleConfig['type'] = $this->detectMetadataDriver($bundleDir, $container);
  147         }
  148 
  149         if (!$bundleConfig['type']) {
  150             // skip this bundle, no mapping information was found.
  151             return false;
  152         }
  153 
  154         if (!$bundleConfig['dir']) {
  155             if (\in_array($bundleConfig['type'], ['annotation', 'staticphp'])) {
  156                 $bundleConfig['dir'] = $bundleDir.'/'.$this->getMappingObjectDefaultName();
  157             } else {
  158                 $bundleConfig['dir'] = $bundleDir.'/'.$this->getMappingResourceConfigDirectory();
  159             }
  160         } else {
  161             $bundleConfig['dir'] = $bundleDir.'/'.$bundleConfig['dir'];
  162         }
  163 
  164         if (!$bundleConfig['prefix']) {
  165             $bundleConfig['prefix'] = $bundle->getNamespaceName().'\\'.$this->getMappingObjectDefaultName();
  166         }
  167 
  168         return $bundleConfig;
  169     }
  170 
  171     /**
  172      * Register all the collected mapping information with the object manager by registering the appropriate mapping drivers.
  173      *
  174      * @param array            $objectManager
  175      * @param ContainerBuilder $container     A ContainerBuilder instance
  176      */
  177     protected function registerMappingDrivers($objectManager, ContainerBuilder $container)
  178     {
  179         // configure metadata driver for each bundle based on the type of mapping files found
  180         if ($container->hasDefinition($this->getObjectManagerElementName($objectManager['name'].'_metadata_driver'))) {
  181             $chainDriverDef = $container->getDefinition($this->getObjectManagerElementName($objectManager['name'].'_metadata_driver'));
  182         } else {
  183             $chainDriverDef = new Definition('%'.$this->getObjectManagerElementName('metadata.driver_chain.class%'));
  184             $chainDriverDef->setPublic(false);
  185         }
  186 
  187         foreach ($this->drivers as $driverType => $driverPaths) {
  188             $mappingService = $this->getObjectManagerElementName($objectManager['name'].'_'.$driverType.'_metadata_driver');
  189             if ($container->hasDefinition($mappingService)) {
  190                 $mappingDriverDef = $container->getDefinition($mappingService);
  191                 $args = $mappingDriverDef->getArguments();
  192                 if ('annotation' == $driverType) {
  193                     $args[1] = array_merge(array_values($driverPaths), $args[1]);
  194                 } else {
  195                     $args[0] = array_merge(array_values($driverPaths), $args[0]);
  196                 }
  197                 $mappingDriverDef->setArguments($args);
  198             } elseif ('annotation' == $driverType) {
  199                 $mappingDriverDef = new Definition('%'.$this->getObjectManagerElementName('metadata.'.$driverType.'.class%'), [
  200                     new Reference($this->getObjectManagerElementName('metadata.annotation_reader')),
  201                     array_values($driverPaths),
  202                 ]);
  203             } else {
  204                 $mappingDriverDef = new Definition('%'.$this->getObjectManagerElementName('metadata.'.$driverType.'.class%'), [
  205                     array_values($driverPaths),
  206                 ]);
  207             }
  208             $mappingDriverDef->setPublic(false);
  209             if (false !== strpos($mappingDriverDef->getClass(), 'yml') || false !== strpos($mappingDriverDef->getClass(), 'xml')) {
  210                 $mappingDriverDef->setArguments([array_flip($driverPaths)]);
  211                 $mappingDriverDef->addMethodCall('setGlobalBasename', ['mapping']);
  212             }
  213 
  214             $container->setDefinition($mappingService, $mappingDriverDef);
  215 
  216             foreach ($driverPaths as $prefix => $driverPath) {
  217                 $chainDriverDef->addMethodCall('addDriver', [new Reference($mappingService), $prefix]);
  218             }
  219         }
  220 
  221         $container->setDefinition($this->getObjectManagerElementName($objectManager['name'].'_metadata_driver'), $chainDriverDef);
  222     }
  223 
  224     /**
  225      * Assertion if the specified mapping information is valid.
  226      *
  227      * @param string $objectManagerName
  228      *
  229      * @throws \InvalidArgumentException
  230      */
  231     protected function assertValidMappingConfiguration(array $mappingConfig, $objectManagerName)
  232     {
  233         if (!$mappingConfig['type'] || !$mappingConfig['dir'] || !$mappingConfig['prefix']) {
  234             throw new \InvalidArgumentException(sprintf('Mapping definitions for Doctrine manager "%s" require at least the "type", "dir" and "prefix" options.', $objectManagerName));
  235         }
  236 
  237         if (!is_dir($mappingConfig['dir'])) {
  238             throw new \InvalidArgumentException(sprintf('Specified non-existing directory "%s" as Doctrine mapping source.', $mappingConfig['dir']));
  239         }
  240 
  241         if (!\in_array($mappingConfig['type'], ['xml', 'yml', 'annotation', 'php', 'staticphp'])) {
  242             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')));
  243         }
  244     }
  245 
  246     /**
  247      * Detects what metadata driver to use for the supplied directory.
  248      *
  249      * @param string           $dir       A directory path
  250      * @param ContainerBuilder $container A ContainerBuilder instance
  251      *
  252      * @return string|null A metadata driver short name, if one can be detected
  253      */
  254     protected function detectMetadataDriver($dir, ContainerBuilder $container)
  255     {
  256         $configPath = $this->getMappingResourceConfigDirectory();
  257         $extension = $this->getMappingResourceExtension();
  258 
  259         if (glob($dir.'/'.$configPath.'/*.'.$extension.'.xml', GLOB_NOSORT)) {
  260             $driver = 'xml';
  261         } elseif (glob($dir.'/'.$configPath.'/*.'.$extension.'.yml', GLOB_NOSORT)) {
  262             $driver = 'yml';
  263         } elseif (glob($dir.'/'.$configPath.'/*.'.$extension.'.php', GLOB_NOSORT)) {
  264             $driver = 'php';
  265         } else {
  266             // add the closest existing directory as a resource
  267             $resource = $dir.'/'.$configPath;
  268             while (!is_dir($resource)) {
  269                 $resource = \dirname($resource);
  270             }
  271             $container->fileExists($resource, false);
  272 
  273             return $container->fileExists($dir.'/'.$this->getMappingObjectDefaultName(), false) ? 'annotation' : null;
  274         }
  275         $container->fileExists($dir.'/'.$configPath, false);
  276 
  277         return $driver;
  278     }
  279 
  280     /**
  281      * Loads a configured object manager metadata, query or result cache driver.
  282      *
  283      * @param array            $objectManager A configured object manager
  284      * @param ContainerBuilder $container     A ContainerBuilder instance
  285      * @param string           $cacheName
  286      *
  287      * @throws \InvalidArgumentException in case of unknown driver type
  288      */
  289     protected function loadObjectManagerCacheDriver(array $objectManager, ContainerBuilder $container, $cacheName)
  290     {
  291         $this->loadCacheDriver($cacheName, $objectManager['name'], $objectManager[$cacheName.'_driver'], $container);
  292     }
  293 
  294     /**
  295      * Loads a cache driver.
  296      *
  297      * @param string           $cacheName         The cache driver name
  298      * @param string           $objectManagerName The object manager name
  299      * @param array            $cacheDriver       The cache driver mapping
  300      * @param ContainerBuilder $container         The ContainerBuilder instance
  301      *
  302      * @return string
  303      *
  304      * @throws \InvalidArgumentException
  305      */
  306     protected function loadCacheDriver($cacheName, $objectManagerName, array $cacheDriver, ContainerBuilder $container)
  307     {
  308         $cacheDriverServiceId = $this->getObjectManagerElementName($objectManagerName.'_'.$cacheName);
  309 
  310         switch ($cacheDriver['type']) {
  311             case 'service':
  312                 $container->setAlias($cacheDriverServiceId, new Alias($cacheDriver['id'], false));
  313 
  314                 return $cacheDriverServiceId;
  315             case 'memcache':
  316                 $memcacheClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%'.$this->getObjectManagerElementName('cache.memcache.class').'%';
  317                 $memcacheInstanceClass = !empty($cacheDriver['instance_class']) ? $cacheDriver['instance_class'] : '%'.$this->getObjectManagerElementName('cache.memcache_instance.class').'%';
  318                 $memcacheHost = !empty($cacheDriver['host']) ? $cacheDriver['host'] : '%'.$this->getObjectManagerElementName('cache.memcache_host').'%';
  319                 $memcachePort = !empty($cacheDriver['port']) || (isset($cacheDriver['port']) && 0 === $cacheDriver['port']) ? $cacheDriver['port'] : '%'.$this->getObjectManagerElementName('cache.memcache_port').'%';
  320                 $cacheDef = new Definition($memcacheClass);
  321                 $memcacheInstance = new Definition($memcacheInstanceClass);
  322                 $memcacheInstance->setPrivate(true);
  323                 $memcacheInstance->addMethodCall('connect', [
  324                     $memcacheHost, $memcachePort,
  325                 ]);
  326                 $container->setDefinition($this->getObjectManagerElementName(sprintf('%s_memcache_instance', $objectManagerName)), $memcacheInstance);
  327                 $cacheDef->addMethodCall('setMemcache', [new Reference($this->getObjectManagerElementName(sprintf('%s_memcache_instance', $objectManagerName)))]);
  328                 break;
  329             case 'memcached':
  330                 $memcachedClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%'.$this->getObjectManagerElementName('cache.memcached.class').'%';
  331                 $memcachedInstanceClass = !empty($cacheDriver['instance_class']) ? $cacheDriver['instance_class'] : '%'.$this->getObjectManagerElementName('cache.memcached_instance.class').'%';
  332                 $memcachedHost = !empty($cacheDriver['host']) ? $cacheDriver['host'] : '%'.$this->getObjectManagerElementName('cache.memcached_host').'%';
  333                 $memcachedPort = !empty($cacheDriver['port']) ? $cacheDriver['port'] : '%'.$this->getObjectManagerElementName('cache.memcached_port').'%';
  334                 $cacheDef = new Definition($memcachedClass);
  335                 $memcachedInstance = new Definition($memcachedInstanceClass);
  336                 $memcachedInstance->setPrivate(true);
  337                 $memcachedInstance->addMethodCall('addServer', [
  338                     $memcachedHost, $memcachedPort,
  339                 ]);
  340                 $container->setDefinition($this->getObjectManagerElementName(sprintf('%s_memcached_instance', $objectManagerName)), $memcachedInstance);
  341                 $cacheDef->addMethodCall('setMemcached', [new Reference($this->getObjectManagerElementName(sprintf('%s_memcached_instance', $objectManagerName)))]);
  342                 break;
  343              case 'redis':
  344                 $redisClass = !empty($cacheDriver['class']) ? $cacheDriver['class'] : '%'.$this->getObjectManagerElementName('cache.redis.class').'%';
  345                 $redisInstanceClass = !empty($cacheDriver['instance_class']) ? $cacheDriver['instance_class'] : '%'.$this->getObjectManagerElementName('cache.redis_instance.class').'%';
  346                 $redisHost = !empty($cacheDriver['host']) ? $cacheDriver['host'] : '%'.$this->getObjectManagerElementName('cache.redis_host').'%';
  347                 $redisPort = !empty($cacheDriver['port']) ? $cacheDriver['port'] : '%'.$this->getObjectManagerElementName('cache.redis_port').'%';
  348                 $cacheDef = new Definition($redisClass);
  349                 $redisInstance = new Definition($redisInstanceClass);
  350                 $redisInstance->setPrivate(true);
  351                 $redisInstance->addMethodCall('connect', [
  352                     $redisHost, $redisPort,
  353                 ]);
  354                 $container->setDefinition($this->getObjectManagerElementName(sprintf('%s_redis_instance', $objectManagerName)), $redisInstance);
  355                 $cacheDef->addMethodCall('setRedis', [new Reference($this->getObjectManagerElementName(sprintf('%s_redis_instance', $objectManagerName)))]);
  356                 break;
  357             case 'apc':
  358             case 'apcu':
  359             case 'array':
  360             case 'xcache':
  361             case 'wincache':
  362             case 'zenddata':
  363                 $cacheDef = new Definition('%'.$this->getObjectManagerElementName(sprintf('cache.%s.class', $cacheDriver['type'])).'%');
  364                 break;
  365             default:
  366                 throw new \InvalidArgumentException(sprintf('"%s" is an unrecognized Doctrine cache driver.', $cacheDriver['type']));
  367         }
  368 
  369         $cacheDef->setPublic(false);
  370 
  371         if (!isset($cacheDriver['namespace'])) {
  372             // generate a unique namespace for the given application
  373             if ($container->hasParameter('cache.prefix.seed')) {
  374                 $seed = '.'.$container->getParameterBag()->resolveValue($container->getParameter('cache.prefix.seed'));
  375             } else {
  376                 $seed = '_'.$container->getParameter('kernel.root_dir');
  377             }
  378             $seed .= '.'.$container->getParameter('kernel.name').'.'.$container->getParameter('kernel.environment').'.'.$container->getParameter('kernel.debug');
  379             $namespace = 'sf_'.$this->getMappingResourceExtension().'_'.$objectManagerName.'_'.ContainerBuilder::hash($seed);
  380 
  381             $cacheDriver['namespace'] = $namespace;
  382         }
  383 
  384         $cacheDef->addMethodCall('setNamespace', [$cacheDriver['namespace']]);
  385 
  386         $container->setDefinition($cacheDriverServiceId, $cacheDef);
  387 
  388         return $cacheDriverServiceId;
  389     }
  390 
  391     /**
  392      * Returns a modified version of $managerConfigs.
  393      *
  394      * The manager called $autoMappedManager will map all bundles that are not mapped by other managers.
  395      *
  396      * @return array The modified version of $managerConfigs
  397      */
  398     protected function fixManagersAutoMappings(array $managerConfigs, array $bundles)
  399     {
  400         if ($autoMappedManager = $this->validateAutoMapping($managerConfigs)) {
  401             foreach (array_keys($bundles) as $bundle) {
  402                 foreach ($managerConfigs as $manager) {
  403                     if (isset($manager['mappings'][$bundle])) {
  404                         continue 2;
  405                     }
  406                 }
  407                 $managerConfigs[$autoMappedManager]['mappings'][$bundle] = [
  408                     'mapping' => true,
  409                     'is_bundle' => true,
  410                 ];
  411             }
  412             $managerConfigs[$autoMappedManager]['auto_mapping'] = false;
  413         }
  414 
  415         return $managerConfigs;
  416     }
  417 
  418     /**
  419      * Prefixes the relative dependency injection container path with the object manager prefix.
  420      *
  421      * @example $name is 'entity_manager' then the result would be 'doctrine.orm.entity_manager'
  422      *
  423      * @param string $name
  424      *
  425      * @return string
  426      */
  427     abstract protected function getObjectManagerElementName($name);
  428 
  429     /**
  430      * Noun that describes the mapped objects such as Entity or Document.
  431      *
  432      * Will be used for autodetection of persistent objects directory.
  433      *
  434      * @return string
  435      */
  436     abstract protected function getMappingObjectDefaultName();
  437 
  438     /**
  439      * Relative path from the bundle root to the directory where mapping files reside.
  440      *
  441      * @return string
  442      */
  443     abstract protected function getMappingResourceConfigDirectory();
  444 
  445     /**
  446      * Extension used by the mapping files.
  447      *
  448      * @return string
  449      */
  450     abstract protected function getMappingResourceExtension();
  451 
  452     /**
  453      * Search for a manager that is declared as 'auto_mapping' = true.
  454      *
  455      * @return string|null The name of the manager. If no one manager is found, returns null
  456      *
  457      * @throws \LogicException
  458      */
  459     private function validateAutoMapping(array $managerConfigs)
  460     {
  461         $autoMappedManager = null;
  462         foreach ($managerConfigs as $name => $manager) {
  463             if (!$manager['auto_mapping']) {
  464                 continue;
  465             }
  466 
  467             if (null !== $autoMappedManager) {
  468                 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));
  469             }
  470 
  471             $autoMappedManager = $name;
  472         }
  473 
  474         return $autoMappedManager;
  475     }
  476 }