DoctrineMongoDBExtension.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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. * Available options:
  34. *
  35. * * mappings An array of bundle names (as the key)
  36. * and mapping configuration (as the value).
  37. * * default_document_manager The name of the document manager that should be
  38. * marked as the default. Default: default.
  39. * * default_connection If using a single connection, the name to give
  40. * to that connection. Default: default.
  41. * * metadata_cache_driver Options: array (default), apc, memcache, xcache
  42. * * server The server if only specifying one connection
  43. * (e.g. mongodb://localhost:27017)
  44. * * options The connections options if only specifying
  45. * one connection.
  46. * * connections An array of each connection and its configuration
  47. * * document_managers An array of document manager names and
  48. * configuration.
  49. * * default_database The database for a document manager that didn't
  50. * explicitly set a database. Default: default;
  51. * * proxy_namespace Namespace of the generated proxies. Default: Proxies
  52. * * auto_generate_proxy_classes Whether to always regenerate the proxt classes.
  53. * Default: false.
  54. * * hydrator_namespace Namespace of the generated proxies. Default: Hydrators
  55. * * auto_generate_hydrator_classes Whether to always regenerate the proxt classes.
  56. * Default: false.
  57. */
  58. public function load(array $configs, ContainerBuilder $container)
  59. {
  60. // Load DoctrineMongoDBBundle/Resources/config/mongodb.xml
  61. $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
  62. $loader->load('mongodb.xml');
  63. $processor = new Processor();
  64. $configuration = new Configuration();
  65. $config = $processor->process($configuration->getConfigTree(), $configs);
  66. // can't currently default this correctly in Configuration
  67. if (!isset($config['metadata_cache_driver'])) {
  68. $config['metadata_cache_driver'] = array('type' => 'array');
  69. }
  70. // set some options as parameters and unset them
  71. $config = $this->overrideParameters($config, $container);
  72. $this->loadConnections($config, $container);
  73. $this->loadDocumentManagers($config, $container);
  74. $this->loadConstraints($config, $container);
  75. }
  76. /**
  77. * Uses some of the extension options to override DI extension parameters.
  78. *
  79. * @param array $options The available configuration options
  80. * @param ContainerBuilder $container A ContainerBuilder instance
  81. */
  82. protected function overrideParameters($options, ContainerBuilder $container)
  83. {
  84. $overrides = array(
  85. 'default_document_manager',
  86. 'default_connection',
  87. 'proxy_namespace',
  88. 'auto_generate_proxy_classes',
  89. 'hydrator_namespace',
  90. 'auto_generate_hydrator_classes',
  91. 'default_database',
  92. );
  93. foreach ($overrides as $key) {
  94. if (isset($options[$key])) {
  95. $container->setParameter('doctrine.odm.mongodb.'.$key, $options[$key]);
  96. // the option should not be used, the parameter should be referenced
  97. unset($options[$key]);
  98. }
  99. }
  100. return $options;
  101. }
  102. /**
  103. * Loads the document managers configuration.
  104. *
  105. * @param array $config An array of configuration settings
  106. * @param ContainerBuilder $container A ContainerBuilder instance
  107. */
  108. protected function loadDocumentManagers(array $config, ContainerBuilder $container)
  109. {
  110. $documentManagers = $this->getDocumentManagers($config, $container);
  111. foreach ($documentManagers as $name => $documentManager) {
  112. $documentManager['name'] = $name;
  113. $this->loadDocumentManager($documentManager, $container, $config['metadata_cache_driver']);
  114. }
  115. $container->setParameter('doctrine.odm.mongodb.document_managers', array_keys($documentManagers));
  116. }
  117. /**
  118. * Loads a document manager configuration.
  119. *
  120. * @param array $documentManager A document manager configuration array
  121. * @param ContainerBuilder $container A ContainerBuilder instance
  122. * @param array $defaultMetadataCache The default metadata cache configuration array
  123. */
  124. protected function loadDocumentManager(array $documentManager, ContainerBuilder $container, $defaultMetadataCache)
  125. {
  126. $defaultDocumentManager = $container->getParameter('doctrine.odm.mongodb.default_document_manager');
  127. $defaultDatabase = isset($documentManager['default_database']) ? $documentManager['default_database'] : $container->getParameter('doctrine.odm.mongodb.default_database');
  128. $configServiceName = sprintf('doctrine.odm.mongodb.%s_configuration', $documentManager['name']);
  129. if ($container->hasDefinition($configServiceName)) {
  130. $odmConfigDef = $container->getDefinition($configServiceName);
  131. } else {
  132. $odmConfigDef = new Definition('%doctrine.odm.mongodb.configuration_class%');
  133. $container->setDefinition($configServiceName, $odmConfigDef);
  134. }
  135. $this->loadDocumentManagerBundlesMappingInformation($documentManager, $odmConfigDef, $container);
  136. $this->loadDocumentManagerMetadataCacheDriver($documentManager, $container, $defaultMetadataCache);
  137. $methods = array(
  138. 'setMetadataCacheImpl' => new Reference(sprintf('doctrine.odm.mongodb.%s_metadata_cache', $documentManager['name'])),
  139. 'setMetadataDriverImpl' => new Reference(sprintf('doctrine.odm.mongodb.%s_metadata_driver', $documentManager['name'])),
  140. 'setProxyDir' => '%kernel.cache_dir%'.'/doctrine/odm/mongodb/Proxies',
  141. 'setProxyNamespace' => '%doctrine.odm.mongodb.proxy_namespace%',
  142. 'setAutoGenerateProxyClasses' => '%doctrine.odm.mongodb.auto_generate_proxy_classes%',
  143. 'setHydratorDir' => '%kernel.cache_dir%'.'/doctrine/odm/mongodb/Hydrators',
  144. 'setHydratorNamespace' => '%doctrine.odm.mongodb.hydrator_namespace%',
  145. 'setAutoGenerateHydratorClasses' => '%doctrine.odm.mongodb.auto_generate_hydrator_classes%',
  146. 'setDefaultDB' => $defaultDatabase,
  147. 'setLoggerCallable' => array(new Reference('doctrine.odm.mongodb.logger'), 'logQuery'),
  148. );
  149. foreach ($methods as $method => $arg) {
  150. if ($odmConfigDef->hasMethodCall($method)) {
  151. $odmConfigDef->removeMethodCall($method);
  152. }
  153. $odmConfigDef->addMethodCall($method, array($arg));
  154. }
  155. // event manager
  156. $eventManagerName = isset($documentManager['event_manager']) ? $documentManager['event_manager'] : $documentManager['name'];
  157. $eventManagerId = sprintf('doctrine.odm.mongodb.%s_event_manager', $eventManagerName);
  158. if (!$container->hasDefinition($eventManagerId)) {
  159. $eventManagerDef = new Definition('%doctrine.odm.mongodb.event_manager_class%');
  160. $eventManagerDef->addTag('doctrine.odm.mongodb.event_manager');
  161. $eventManagerDef->setPublic(false);
  162. $container->setDefinition($eventManagerId, $eventManagerDef);
  163. }
  164. $odmDmArgs = array(
  165. new Reference(sprintf('doctrine.odm.mongodb.%s_connection', isset($documentManager['connection']) ? $documentManager['connection'] : $documentManager['name'])),
  166. new Reference(sprintf('doctrine.odm.mongodb.%s_configuration', $documentManager['name'])),
  167. new Reference($eventManagerId),
  168. );
  169. $odmDmDef = new Definition('%doctrine.odm.mongodb.document_manager_class%', $odmDmArgs);
  170. $odmDmDef->setFactoryClass('%doctrine.odm.mongodb.document_manager_class%');
  171. $odmDmDef->setFactoryMethod('create');
  172. $odmDmDef->addTag('doctrine.odm.mongodb.document_manager');
  173. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_document_manager', $documentManager['name']), $odmDmDef);
  174. if ($documentManager['name'] == $defaultDocumentManager) {
  175. $container->setAlias(
  176. 'doctrine.odm.mongodb.document_manager',
  177. new Alias(sprintf('doctrine.odm.mongodb.%s_document_manager', $documentManager['name']))
  178. );
  179. $container->setAlias(
  180. 'doctrine.odm.mongodb.event_manager',
  181. new Alias(sprintf('doctrine.odm.mongodb.%s_event_manager', $documentManager['name']))
  182. );
  183. }
  184. }
  185. /**
  186. * Gets the configured document managers.
  187. *
  188. * @param array $config An array of configuration settings
  189. * @param ContainerBuilder $container A ContainerBuilder instance
  190. */
  191. protected function getDocumentManagers(array $config, ContainerBuilder $container)
  192. {
  193. $defaultDocumentManager = $container->getParameter('doctrine.odm.mongodb.default_document_manager');
  194. $documentManagers = array();
  195. if (count($config['document_managers'])) {
  196. $configDocumentManagers = $config['document_managers'];
  197. foreach ($configDocumentManagers as $name => $documentManager) {
  198. $documentManagers[isset($documentManager['id']) ? $documentManager['id'] : $name] = $documentManager;
  199. }
  200. } else {
  201. $documentManagers = array($defaultDocumentManager => $config);
  202. }
  203. return $documentManagers;
  204. }
  205. /**
  206. * Loads the configured document manager metadata cache driver.
  207. *
  208. * @param array $config A configured document manager array
  209. * @param ContainerBuilder $container A ContainerBuilder instance
  210. * @param array $defaultMetadataCache The default metadata cache configuration array
  211. */
  212. protected function loadDocumentManagerMetadataCacheDriver(array $documentManager, ContainerBuilder $container, $defaultMetadataCache)
  213. {
  214. $dmMetadataCacheDriver = isset($documentManager['metadata_cache_driver']) ? $documentManager['metadata_cache_driver'] : $defaultMetadataCache;
  215. $type = $dmMetadataCacheDriver['type'];
  216. if ('memcache' === $type) {
  217. $memcacheClass = isset($dmMetadataCacheDriver['class']) ? $dmMetadataCacheDriver['class'] : sprintf('%%doctrine.odm.mongodb.cache.%s_class%%', $type);
  218. $cacheDef = new Definition($memcacheClass);
  219. $memcacheHost = isset($dmMetadataCacheDriver['host']) ? $dmMetadataCacheDriver['host'] : '%doctrine.odm.mongodb.cache.memcache_host%';
  220. $memcachePort = isset($dmMetadataCacheDriver['port']) ? $dmMetadataCacheDriver['port'] : '%doctrine.odm.mongodb.cache.memcache_port%';
  221. $memcacheInstanceClass = isset($dmMetadataCacheDriver['instance-class']) ? $dmMetadataCacheDriver['instance-class'] : (isset($dmMetadataCacheDriver['instance_class']) ? $dmMetadataCacheDriver['instance_class'] : '%doctrine.odm.mongodb.cache.memcache_instance_class%');
  222. $memcacheInstance = new Definition($memcacheInstanceClass);
  223. $memcacheInstance->addMethodCall('connect', array($memcacheHost, $memcachePort));
  224. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_memcache_instance', $documentManager['name']), $memcacheInstance);
  225. $cacheDef->addMethodCall('setMemcache', array(new Reference(sprintf('doctrine.odm.mongodb.%s_memcache_instance', $documentManager['name']))));
  226. } else {
  227. $cacheDef = new Definition(sprintf('%%doctrine.odm.mongodb.cache.%s_class%%', $type));
  228. }
  229. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_metadata_cache', $documentManager['name']), $cacheDef);
  230. }
  231. /**
  232. * Loads the configured connections.
  233. *
  234. * @param array $config An array of configuration settings
  235. * @param ContainerBuilder $container A ContainerBuilder instance
  236. */
  237. protected function loadConnections(array $config, ContainerBuilder $container)
  238. {
  239. $connections = $this->getConnections($config, $container);
  240. foreach ($connections as $name => $connection) {
  241. $odmConnArgs = array(
  242. isset($connection['server']) ? $connection['server'] : null,
  243. isset($connection['options']) ? $connection['options'] : array(),
  244. new Reference(sprintf('doctrine.odm.mongodb.%s_configuration', $name))
  245. );
  246. $odmConnDef = new Definition('%doctrine.odm.mongodb.connection_class%', $odmConnArgs);
  247. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_connection', $name), $odmConnDef);
  248. }
  249. }
  250. /**
  251. * Gets the configured connections.
  252. *
  253. * @param array $config An array of configuration settings
  254. * @param ContainerBuilder $container A ContainerBuilder instance
  255. */
  256. protected function getConnections(array $config, ContainerBuilder $container)
  257. {
  258. $defaultConnection = $container->getParameter('doctrine.odm.mongodb.default_connection');
  259. $connections = array();
  260. if (count($config['connections'])) {
  261. $configConnections = $config['connections'];
  262. foreach ($configConnections as $name => $connection) {
  263. $connections[isset($connection['id']) ? $connection['id'] : $name] = $connection;
  264. }
  265. } else {
  266. $connections = array($defaultConnection => $config);
  267. }
  268. return $connections;
  269. }
  270. /**
  271. * Loads an ODM document managers bundle mapping information.
  272. *
  273. * There are two distinct configuration possibilities for mapping information:
  274. *
  275. * 1. Specify a bundle and optionally details where the entity and mapping information reside.
  276. * 2. Specify an arbitrary mapping location.
  277. *
  278. * @example
  279. *
  280. * doctrine.orm:
  281. * mappings:
  282. * MyBundle1: ~
  283. * MyBundle2: yml
  284. * MyBundle3: { type: annotation, dir: Documents/ }
  285. * MyBundle4: { type: xml, dir: Resources/config/doctrine/mapping }
  286. * MyBundle5:
  287. * type: yml
  288. * dir: [bundle-mappings1/, bundle-mappings2/]
  289. * alias: BundleAlias
  290. * arbitrary_key:
  291. * type: xml
  292. * dir: %kernel.dir%/../src/vendor/DoctrineExtensions/lib/DoctrineExtensions/Documents
  293. * prefix: DoctrineExtensions\Documents\
  294. * alias: DExt
  295. *
  296. * In the case of bundles everything is really optional (which leads to autodetection for this bundle) but
  297. * in the mappings key everything except alias is a required argument.
  298. *
  299. * @param array $documentManager A configured ODM entity manager.
  300. * @param Definition A Definition instance
  301. * @param ContainerBuilder $container A ContainerBuilder instance
  302. */
  303. protected function loadDocumentManagerBundlesMappingInformation(array $documentManager, Definition $odmConfigDef, ContainerBuilder $container)
  304. {
  305. // reset state of drivers and alias map. They are only used by this methods and children.
  306. $this->drivers = array();
  307. $this->aliasMap = array();
  308. $this->loadMappingInformation($documentManager, $container);
  309. $this->registerMappingDrivers($documentManager, $container);
  310. if ($odmConfigDef->hasMethodCall('setDocumentNamespaces')) {
  311. // TODO: Can we make a method out of it on Definition? replaceMethodArguments() or something.
  312. $calls = $odmConfigDef->getMethodCalls();
  313. foreach ($calls as $call) {
  314. if ($call[0] == 'setDocumentNamespaces') {
  315. $this->aliasMap = array_merge($call[1][0], $this->aliasMap);
  316. }
  317. }
  318. $method = $odmConfigDef->removeMethodCall('setDocumentNamespaces');
  319. }
  320. $odmConfigDef->addMethodCall('setDocumentNamespaces', array($this->aliasMap));
  321. }
  322. protected function loadConstraints($config, ContainerBuilder $container)
  323. {
  324. if ($container->hasParameter('validator.annotations.namespaces')) {
  325. $container->setParameter('validator.annotations.namespaces', array_merge(
  326. $container->getParameter('validator.annotations.namespaces'),
  327. array('mongodb' => 'Symfony\Bundle\DoctrineMongoDBBundle\Validator\Constraints\\')
  328. ));
  329. }
  330. }
  331. protected function getObjectManagerElementName($name)
  332. {
  333. return 'doctrine.odm.mongodb.' . $name;
  334. }
  335. protected function getMappingObjectDefaultName()
  336. {
  337. return 'Document';
  338. }
  339. protected function getMappingResourceConfigDirectory()
  340. {
  341. return 'Resources/config/doctrine/metadata/mongodb';
  342. }
  343. /**
  344. * Returns the namespace to be used for this extension (XML namespace).
  345. *
  346. * @return string The XML namespace
  347. */
  348. public function getNamespace()
  349. {
  350. return 'http://symfony.com/schema/dic/doctrine/odm/mongodb';
  351. }
  352. /**
  353. * @return string
  354. */
  355. public function getXsdValidationBasePath()
  356. {
  357. return __DIR__.'/../Resources/config/schema';
  358. }
  359. }