DoctrineMongoDBExtension.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\DoctrineMongoDBBundle\DependencyInjection;
  11. use Symfony\Component\HttpKernel\DependencyInjection\Extension;
  12. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  13. use Symfony\Component\DependencyInjection\ContainerBuilder;
  14. use Symfony\Component\DependencyInjection\Alias;
  15. use Symfony\Component\DependencyInjection\Reference;
  16. use Symfony\Component\DependencyInjection\Definition;
  17. use Symfony\Component\Config\Resource\FileResource;
  18. use Symfony\Component\Config\FileLocator;
  19. use Symfony\Bundle\DoctrineAbstractBundle\DependencyInjection\AbstractDoctrineExtension;
  20. use Symfony\Component\Config\Definition\Processor;
  21. /**
  22. * Doctrine MongoDB ODM extension.
  23. *
  24. * @author Bulat Shakirzyanov <bulat@theopenskyproject.com>
  25. * @author Kris Wallsmith <kris.wallsmith@symfony.com>
  26. * @author Jonathan H. Wage <jonwage@gmail.com>
  27. */
  28. class DoctrineMongoDBExtension extends AbstractDoctrineExtension
  29. {
  30. /**
  31. * Responds to the doctrine_mongo_db configuration parameter.
  32. */
  33. public function load(array $configs, ContainerBuilder $container)
  34. {
  35. // Load DoctrineMongoDBBundle/Resources/config/mongodb.xml
  36. $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
  37. $loader->load('mongodb.xml');
  38. $processor = new Processor();
  39. $configuration = new Configuration($container->getParameter('kernel.debug'));
  40. $config = $processor->process($configuration->getConfigTree(), $configs);
  41. // can't currently default this correctly in Configuration
  42. if (!isset($config['metadata_cache_driver'])) {
  43. $config['metadata_cache_driver'] = array('type' => 'array');
  44. }
  45. if (empty ($config['default_connection'])) {
  46. $keys = array_keys($config['connections']);
  47. $config['default_connection'] = reset($keys);
  48. }
  49. if (empty ($config['default_document_manager'])) {
  50. $keys = array_keys($config['document_managers']);
  51. $config['default_document_manager'] = reset($keys);
  52. }
  53. // set some options as parameters and unset them
  54. $config = $this->overrideParameters($config, $container);
  55. // load the connections
  56. $this->loadConnections($config['connections'], $container);
  57. // load the document managers
  58. $this->loadDocumentManagers(
  59. $config['document_managers'],
  60. $config['default_document_manager'],
  61. $config['default_database'],
  62. $config['metadata_cache_driver'],
  63. $container
  64. );
  65. $this->loadConstraints($container);
  66. }
  67. /**
  68. * Uses some of the extension options to override DI extension parameters.
  69. *
  70. * @param array $options The available configuration options
  71. * @param ContainerBuilder $container A ContainerBuilder instance
  72. */
  73. protected function overrideParameters($options, ContainerBuilder $container)
  74. {
  75. $overrides = array(
  76. 'proxy_namespace',
  77. 'auto_generate_proxy_classes',
  78. 'hydrator_namespace',
  79. 'auto_generate_hydrator_classes',
  80. );
  81. foreach ($overrides as $key) {
  82. if (isset($options[$key])) {
  83. $container->setParameter('doctrine.odm.mongodb.'.$key, $options[$key]);
  84. // the option should not be used, the parameter should be referenced
  85. unset($options[$key]);
  86. }
  87. }
  88. return $options;
  89. }
  90. /**
  91. * Loads the document managers configuration.
  92. *
  93. * @param array $dmConfigs An array of document manager configs
  94. * @param string $defaultDM The default document manager name
  95. * @param string $defaultDB The default db name
  96. * @param string $defaultMetadataCache The default metadata cache configuration
  97. * @param ContainerBuilder $container A ContainerBuilder instance
  98. */
  99. protected function loadDocumentManagers(array $dmConfigs, $defaultDM, $defaultDB, $defaultMetadataCache, ContainerBuilder $container)
  100. {
  101. foreach ($dmConfigs as $name => $documentManager) {
  102. $documentManager['name'] = $name;
  103. $this->loadDocumentManager(
  104. $documentManager,
  105. $defaultDM,
  106. $defaultDB,
  107. $defaultMetadataCache,
  108. $container
  109. );
  110. }
  111. $container->setParameter('doctrine.odm.mongodb.document_managers', array_keys($dmConfigs));
  112. }
  113. /**
  114. * Loads a document manager configuration.
  115. *
  116. * @param array $documentManager A document manager configuration array
  117. * @param string $defaultDM The default document manager name
  118. * @param string $defaultDB The default db name
  119. * @param string $defaultMetadataCache The default metadata cache configuration
  120. * @param ContainerBuilder $container A ContainerBuilder instance
  121. */
  122. protected function loadDocumentManager(array $documentManager, $defaultDM, $defaultDB, $defaultMetadataCache, ContainerBuilder $container)
  123. {
  124. $defaultDatabase = isset($documentManager['default_database']) ? $documentManager['default_database'] : $defaultDB;
  125. $configServiceName = sprintf('doctrine.odm.mongodb.%s_configuration', $documentManager['name']);
  126. if ($container->hasDefinition($configServiceName)) {
  127. $odmConfigDef = $container->getDefinition($configServiceName);
  128. } else {
  129. $odmConfigDef = new Definition('%doctrine.odm.mongodb.configuration_class%');
  130. $container->setDefinition($configServiceName, $odmConfigDef);
  131. }
  132. $this->loadDocumentManagerBundlesMappingInformation($documentManager, $odmConfigDef, $container);
  133. $this->loadDocumentManagerMetadataCacheDriver($documentManager, $container, $defaultMetadataCache);
  134. $methods = array(
  135. 'setMetadataCacheImpl' => new Reference(sprintf('doctrine.odm.mongodb.%s_metadata_cache', $documentManager['name'])),
  136. 'setMetadataDriverImpl' => new Reference(sprintf('doctrine.odm.mongodb.%s_metadata_driver', $documentManager['name'])),
  137. 'setProxyDir' => '%kernel.cache_dir%'.'/doctrine/odm/mongodb/Proxies',
  138. 'setProxyNamespace' => '%doctrine.odm.mongodb.proxy_namespace%',
  139. 'setAutoGenerateProxyClasses' => '%doctrine.odm.mongodb.auto_generate_proxy_classes%',
  140. 'setHydratorDir' => '%kernel.cache_dir%'.'/doctrine/odm/mongodb/Hydrators',
  141. 'setHydratorNamespace' => '%doctrine.odm.mongodb.hydrator_namespace%',
  142. 'setAutoGenerateHydratorClasses' => '%doctrine.odm.mongodb.auto_generate_hydrator_classes%',
  143. 'setDefaultDB' => $defaultDatabase,
  144. );
  145. if ($documentManager['logging']) {
  146. $methods['setLoggerCallable'] = array(new Reference('doctrine.odm.mongodb.logger'), 'logQuery');
  147. }
  148. foreach ($methods as $method => $arg) {
  149. if ($odmConfigDef->hasMethodCall($method)) {
  150. $odmConfigDef->removeMethodCall($method);
  151. }
  152. $odmConfigDef->addMethodCall($method, array($arg));
  153. }
  154. // event manager
  155. $eventManagerName = isset($documentManager['event_manager']) ? $documentManager['event_manager'] : $documentManager['name'];
  156. $eventManagerId = sprintf('doctrine.odm.mongodb.%s_event_manager', $eventManagerName);
  157. if (!$container->hasDefinition($eventManagerId)) {
  158. $eventManagerDef = new Definition('%doctrine.odm.mongodb.event_manager_class%');
  159. $eventManagerDef->addTag('doctrine.odm.mongodb.event_manager');
  160. $eventManagerDef->setPublic(false);
  161. $container->setDefinition($eventManagerId, $eventManagerDef);
  162. }
  163. $odmDmArgs = array(
  164. new Reference(sprintf('doctrine.odm.mongodb.%s_connection', isset($documentManager['connection']) ? $documentManager['connection'] : $documentManager['name'])),
  165. new Reference(sprintf('doctrine.odm.mongodb.%s_configuration', $documentManager['name'])),
  166. new Reference($eventManagerId),
  167. );
  168. $odmDmDef = new Definition('%doctrine.odm.mongodb.document_manager_class%', $odmDmArgs);
  169. $odmDmDef->setFactoryClass('%doctrine.odm.mongodb.document_manager_class%');
  170. $odmDmDef->setFactoryMethod('create');
  171. $odmDmDef->addTag('doctrine.odm.mongodb.document_manager');
  172. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_document_manager', $documentManager['name']), $odmDmDef);
  173. if ($documentManager['name'] == $defaultDM) {
  174. $container->setAlias(
  175. 'doctrine.odm.mongodb.document_manager',
  176. new Alias(sprintf('doctrine.odm.mongodb.%s_document_manager', $documentManager['name']))
  177. );
  178. $container->setAlias(
  179. 'doctrine.odm.mongodb.event_manager',
  180. new Alias(sprintf('doctrine.odm.mongodb.%s_event_manager', $documentManager['name']))
  181. );
  182. }
  183. }
  184. /**
  185. * Loads the configured document manager metadata cache driver.
  186. *
  187. * @param array $config A configured document manager array
  188. * @param ContainerBuilder $container A ContainerBuilder instance
  189. * @param array $defaultMetadataCache The default metadata cache configuration array
  190. */
  191. protected function loadDocumentManagerMetadataCacheDriver(array $documentManager, ContainerBuilder $container, $defaultMetadataCache)
  192. {
  193. $dmMetadataCacheDriver = isset($documentManager['metadata_cache_driver']) ? $documentManager['metadata_cache_driver'] : $defaultMetadataCache;
  194. $type = $dmMetadataCacheDriver['type'];
  195. if ('memcache' === $type) {
  196. $memcacheClass = isset($dmMetadataCacheDriver['class']) ? $dmMetadataCacheDriver['class'] : sprintf('%%doctrine.odm.mongodb.cache.%s_class%%', $type);
  197. $cacheDef = new Definition($memcacheClass);
  198. $memcacheHost = isset($dmMetadataCacheDriver['host']) ? $dmMetadataCacheDriver['host'] : '%doctrine.odm.mongodb.cache.memcache_host%';
  199. $memcachePort = isset($dmMetadataCacheDriver['port']) ? $dmMetadataCacheDriver['port'] : '%doctrine.odm.mongodb.cache.memcache_port%';
  200. $memcacheInstanceClass = isset($dmMetadataCacheDriver['instance-class']) ? $dmMetadataCacheDriver['instance-class'] : (isset($dmMetadataCacheDriver['instance_class']) ? $dmMetadataCacheDriver['instance_class'] : '%doctrine.odm.mongodb.cache.memcache_instance_class%');
  201. $memcacheInstance = new Definition($memcacheInstanceClass);
  202. $memcacheInstance->addMethodCall('connect', array($memcacheHost, $memcachePort));
  203. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_memcache_instance', $documentManager['name']), $memcacheInstance);
  204. $cacheDef->addMethodCall('setMemcache', array(new Reference(sprintf('doctrine.odm.mongodb.%s_memcache_instance', $documentManager['name']))));
  205. } else {
  206. $cacheDef = new Definition(sprintf('%%doctrine.odm.mongodb.cache.%s_class%%', $type));
  207. }
  208. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_metadata_cache', $documentManager['name']), $cacheDef);
  209. }
  210. /**
  211. * Loads the configured connections.
  212. *
  213. * @param array $config An array of connections configurations
  214. * @param ContainerBuilder $container A ContainerBuilder instance
  215. */
  216. protected function loadConnections(array $connections, ContainerBuilder $container)
  217. {
  218. foreach ($connections as $name => $connection) {
  219. $odmConnArgs = array(
  220. isset($connection['server']) ? $connection['server'] : null,
  221. isset($connection['options']) ? $connection['options'] : array(),
  222. new Reference(sprintf('doctrine.odm.mongodb.%s_configuration', $name))
  223. );
  224. $odmConnDef = new Definition('%doctrine.odm.mongodb.connection_class%', $odmConnArgs);
  225. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_connection', $name), $odmConnDef);
  226. }
  227. }
  228. /**
  229. * Loads an ODM document managers bundle mapping information.
  230. *
  231. * There are two distinct configuration possibilities for mapping information:
  232. *
  233. * 1. Specify a bundle and optionally details where the entity and mapping information reside.
  234. * 2. Specify an arbitrary mapping location.
  235. *
  236. * @example
  237. *
  238. * doctrine.orm:
  239. * mappings:
  240. * MyBundle1: ~
  241. * MyBundle2: yml
  242. * MyBundle3: { type: annotation, dir: Documents/ }
  243. * MyBundle4: { type: xml, dir: Resources/config/doctrine/mapping }
  244. * MyBundle5:
  245. * type: yml
  246. * dir: [bundle-mappings1/, bundle-mappings2/]
  247. * alias: BundleAlias
  248. * arbitrary_key:
  249. * type: xml
  250. * dir: %kernel.dir%/../src/vendor/DoctrineExtensions/lib/DoctrineExtensions/Documents
  251. * prefix: DoctrineExtensions\Documents\
  252. * alias: DExt
  253. *
  254. * In the case of bundles everything is really optional (which leads to autodetection for this bundle) but
  255. * in the mappings key everything except alias is a required argument.
  256. *
  257. * @param array $documentManager A configured ODM entity manager.
  258. * @param Definition A Definition instance
  259. * @param ContainerBuilder $container A ContainerBuilder instance
  260. */
  261. protected function loadDocumentManagerBundlesMappingInformation(array $documentManager, Definition $odmConfigDef, ContainerBuilder $container)
  262. {
  263. // reset state of drivers and alias map. They are only used by this methods and children.
  264. $this->drivers = array();
  265. $this->aliasMap = array();
  266. $this->loadMappingInformation($documentManager, $container);
  267. $this->registerMappingDrivers($documentManager, $container);
  268. if ($odmConfigDef->hasMethodCall('setDocumentNamespaces')) {
  269. // TODO: Can we make a method out of it on Definition? replaceMethodArguments() or something.
  270. $calls = $odmConfigDef->getMethodCalls();
  271. foreach ($calls as $call) {
  272. if ($call[0] == 'setDocumentNamespaces') {
  273. $this->aliasMap = array_merge($call[1][0], $this->aliasMap);
  274. }
  275. }
  276. $method = $odmConfigDef->removeMethodCall('setDocumentNamespaces');
  277. }
  278. $odmConfigDef->addMethodCall('setDocumentNamespaces', array($this->aliasMap));
  279. }
  280. protected function loadConstraints(ContainerBuilder $container)
  281. {
  282. if ($container->hasParameter('validator.annotations.namespaces')) {
  283. $container->setParameter('validator.annotations.namespaces', array_merge(
  284. $container->getParameter('validator.annotations.namespaces'),
  285. array('mongodb' => 'Symfony\Bundle\DoctrineMongoDBBundle\Validator\Constraints\\')
  286. ));
  287. }
  288. }
  289. protected function getObjectManagerElementName($name)
  290. {
  291. return 'doctrine.odm.mongodb.' . $name;
  292. }
  293. protected function getMappingObjectDefaultName()
  294. {
  295. return 'Document';
  296. }
  297. protected function getMappingResourceConfigDirectory()
  298. {
  299. return 'Resources/config/doctrine/metadata/mongodb';
  300. }
  301. /**
  302. * Returns the namespace to be used for this extension (XML namespace).
  303. *
  304. * @return string The XML namespace
  305. */
  306. public function getNamespace()
  307. {
  308. return 'http://symfony.com/schema/dic/doctrine/odm/mongodb';
  309. }
  310. /**
  311. * @return string
  312. */
  313. public function getXsdValidationBasePath()
  314. {
  315. return __DIR__.'/../Resources/config/schema';
  316. }
  317. }