DoctrineMongoDBExtension.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. <?php
  2. namespace Symfony\Bundle\DoctrineMongoDBBundle\DependencyInjection;
  3. use Symfony\Component\DependencyInjection\Extension\Extension;
  4. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  5. use Symfony\Component\DependencyInjection\ContainerBuilder;
  6. use Symfony\Component\DependencyInjection\Reference;
  7. use Symfony\Component\DependencyInjection\Definition;
  8. use Symfony\Component\DependencyInjection\Resource\FileResource;
  9. use Symfony\Bundle\DoctrineAbstractBundle\DependencyInjection\AbstractDoctrineExtension;
  10. /**
  11. * Doctrine MongoDB ODM extension.
  12. *
  13. * @author Bulat Shakirzyanov <bulat@theopenskyproject.com>
  14. * @author Kris Wallsmith <kris.wallsmith@symfony-project.com>
  15. * @author Jonathan H. Wage <jonwage@gmail.com>
  16. */
  17. class DoctrineMongoDBExtension extends AbstractDoctrineExtension
  18. {
  19. /**
  20. * Loads the MongoDB ODM configuration.
  21. *
  22. * Usage example:
  23. *
  24. * <doctrine:mongodb server="mongodb://localhost:27017" />
  25. *
  26. * @param array $config An array of configuration settings
  27. * @param ContainerBuilder $container A ContainerBuilder instance
  28. */
  29. public function mongodbLoad($config, ContainerBuilder $container)
  30. {
  31. $this->createProxyDirectory($container->getParameter('kernel.cache_dir'));
  32. $this->createHydratorDirectory($container->getParameter('kernel.cache_dir'));
  33. $this->loadDefaults($config, $container);
  34. $this->loadConnections($config, $container);
  35. $this->loadDocumentManagers($config, $container);
  36. }
  37. /**
  38. * Create the Doctrine MongoDB ODM Document proxy directory
  39. */
  40. protected function createProxyDirectory($tmpDir)
  41. {
  42. // Create document proxy directory
  43. $proxyCacheDir = $tmpDir.'/doctrine/odm/mongodb/Proxies';
  44. if (!is_dir($proxyCacheDir)) {
  45. if (false === @mkdir($proxyCacheDir, 0777, true)) {
  46. die(sprintf('Unable to create the Doctrine Proxy directory (%s)', dirname($proxyCacheDir)));
  47. }
  48. } elseif (!is_writable($proxyCacheDir)) {
  49. die(sprintf('Unable to write in the Doctrine Proxy directory (%s)', $proxyCacheDir));
  50. }
  51. }
  52. /**
  53. * Create the Doctrine MongoDB ODM Document hydrator directory
  54. */
  55. protected function createHydratorDirectory($tmpDir)
  56. {
  57. // Create document hydrator directory
  58. $hydratorCacheDir = $tmpDir.'/doctrine/odm/mongodb/Hydrators';
  59. if (!is_dir($hydratorCacheDir)) {
  60. if (false === @mkdir($hydratorCacheDir, 0777, true)) {
  61. die(sprintf('Unable to create the Doctrine Hydrator directory (%s)', dirname($hydratorCacheDir)));
  62. }
  63. } elseif (!is_writable($hydratorCacheDir)) {
  64. die(sprintf('Unable to write in the Doctrine Hydrator directory (%s)', $hydratorCacheDir));
  65. }
  66. }
  67. /**
  68. * Loads the default configuration.
  69. *
  70. * @param array $config An array of configuration settings
  71. * @param ContainerBuilder $container A ContainerBuilder instance
  72. */
  73. protected function loadDefaults(array $config, ContainerBuilder $container)
  74. {
  75. if (!$container->hasDefinition('doctrine.odm.mongodb.metadata.annotation')) {
  76. // Load DoctrineMongoDBBundle/Resources/config/mongodb.xml
  77. $loader = new XmlFileLoader($container, __DIR__.'/../Resources/config');
  78. $loader->load('mongodb.xml');
  79. }
  80. // Allow these application configuration options to override the defaults
  81. $options = array(
  82. 'default_document_manager',
  83. 'default_connection',
  84. 'cache_driver',
  85. 'metadata_cache_driver',
  86. 'proxy_namespace',
  87. 'auto_generate_proxy_classes',
  88. 'hydrator_namespace',
  89. 'auto_generate_hydrator_classes',
  90. 'default_database',
  91. );
  92. foreach ($options as $key) {
  93. if (isset($config[$key])) {
  94. $container->setParameter('doctrine.odm.mongodb.'.$key, $config[$key]);
  95. }
  96. $nKey = str_replace('_', '-', $key);
  97. if (isset($config[$nKey])) {
  98. $container->setParameter('doctrine.odm.mongodb.'.$key, $config[$nKey]);
  99. }
  100. }
  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);
  114. }
  115. }
  116. /**
  117. * Loads a document manager configuration.
  118. *
  119. * @param array $documentManager A document manager configuration array
  120. * @param ContainerBuilder $container A ContainerBuilder instance
  121. */
  122. protected function loadDocumentManager(array $documentManager, ContainerBuilder $container)
  123. {
  124. $defaultDocumentManager = $container->getParameter('doctrine.odm.mongodb.default_document_manager');
  125. $defaultDatabase = isset($documentManager['default_database']) ? $documentManager['default_database'] : $container->getParameter('doctrine.odm.mongodb.default_database');
  126. $proxyCacheDir = $container->getParameter('kernel.cache_dir').'/doctrine/odm/mongodb/Proxies';
  127. $hydratorCacheDir = $container->getParameter('kernel.cache_dir').'/doctrine/odm/mongodb/Hydrators';
  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);
  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' => $proxyCacheDir,
  141. 'setProxyNamespace' => $container->getParameter('doctrine.odm.mongodb.proxy_namespace'),
  142. 'setAutoGenerateProxyClasses' => $container->getParameter('doctrine.odm.mongodb.auto_generate_proxy_classes'),
  143. 'setHydratorDir' => $hydratorCacheDir,
  144. 'setHydratorNamespace' => $container->getParameter('doctrine.odm.mongodb.hydrator_namespace'),
  145. 'setAutoGenerateHydratorClasses' => $container->getParameter('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->addMethodCall('loadTaggedEventListeners', array(
  161. new Reference('service_container'),
  162. ));
  163. $eventManagerDef->addMethodCall('loadTaggedEventListeners', array(
  164. new Reference('service_container'),
  165. sprintf('doctrine.odm.mongodb.%s_event_listener', $eventManagerName),
  166. ));
  167. $eventManagerDef->addMethodCall('loadTaggedEventSubscribers', array(
  168. new Reference('service_container'),
  169. ));
  170. $eventManagerDef->addMethodCall('loadTaggedEventSubscribers', array(
  171. new Reference('service_container'),
  172. sprintf('doctrine.odm.mongodb.%s_event_subscriber', $eventManagerName),
  173. ));
  174. $container->setDefinition($eventManagerId, $eventManagerDef);
  175. }
  176. $odmDmArgs = array(
  177. new Reference(sprintf('doctrine.odm.mongodb.%s_connection', isset($documentManager['connection']) ? $documentManager['connection'] : $documentManager['name'])),
  178. new Reference(sprintf('doctrine.odm.mongodb.%s_configuration', $documentManager['name'])),
  179. new Reference($eventManagerId),
  180. );
  181. $odmDmDef = new Definition('%doctrine.odm.mongodb.document_manager_class%', $odmDmArgs);
  182. $odmDmDef->setFactoryMethod('create');
  183. $odmDmDef->addTag('doctrine.odm.mongodb.document_manager');
  184. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_document_manager', $documentManager['name']), $odmDmDef);
  185. if ($documentManager['name'] == $defaultDocumentManager) {
  186. $container->setAlias(
  187. 'doctrine.odm.mongodb.document_manager',
  188. sprintf('doctrine.odm.mongodb.%s_document_manager', $documentManager['name'])
  189. );
  190. }
  191. }
  192. /**
  193. * Gets the configured document managers.
  194. *
  195. * @param array $config An array of configuration settings
  196. * @param ContainerBuilder $container A ContainerBuilder instance
  197. */
  198. protected function getDocumentManagers(array $config, ContainerBuilder $container)
  199. {
  200. $defaultDocumentManager = $container->getParameter('doctrine.odm.mongodb.default_document_manager');
  201. $documentManagers = array();
  202. if (isset($config['document-managers'])) {
  203. $config['document_managers'] = $config['document-managers'];
  204. }
  205. if (isset($config['document_managers'])) {
  206. $configDocumentManagers = $config['document_managers'];
  207. if (isset($config['document_managers']['document-manager'])) {
  208. $config['document_managers']['document_manager'] = $config['document_managers']['document-manager'];
  209. }
  210. if (isset($config['document_managers']['document_manager']) && isset($config['document_managers']['document_manager'][0])) {
  211. // Multiple document managers
  212. $configDocumentManagers = $config['document_managers']['document_manager'];
  213. }
  214. foreach ($configDocumentManagers as $name => $documentManager) {
  215. $documentManagers[isset($documentManager['id']) ? $documentManager['id'] : $name] = $documentManager;
  216. }
  217. } else {
  218. $documentManagers = array($defaultDocumentManager => $config);
  219. }
  220. return $documentManagers;
  221. }
  222. /**
  223. * Loads the configured document manager metadata cache driver.
  224. *
  225. * @param array $config A configured document manager array
  226. * @param ContainerBuilder $container A ContainerBuilder instance
  227. */
  228. protected function loadDocumentManagerMetadataCacheDriver(array $documentManager, ContainerBuilder $container)
  229. {
  230. $metadataCacheDriver = $container->getParameter('doctrine.odm.mongodb.metadata_cache_driver');
  231. $dmMetadataCacheDriver = isset($documentManager['metadata-cache-driver']) ? $documentManager['metadata-cache-driver'] : (isset($documentManager['metadata_cache_driver']) ? $documentManager['metadata_cache_driver'] : $metadataCacheDriver);
  232. $type = is_array($dmMetadataCacheDriver) && isset($dmMetadataCacheDriver['type']) ? $dmMetadataCacheDriver['type'] : $dmMetadataCacheDriver;
  233. if ('memcache' === $type) {
  234. $memcacheClass = isset($dmMetadataCacheDriver['class']) ? $dmMetadataCacheDriver['class'] : sprintf('%%doctrine.odm.mongodb.cache.%s_class%%', $type);
  235. $cacheDef = new Definition($memcacheClass);
  236. $memcacheHost = isset($dmMetadataCacheDriver['host']) ? $dmMetadataCacheDriver['host'] : '%doctrine.odm.mongodb.cache.memcache_host%';
  237. $memcachePort = isset($dmMetadataCacheDriver['port']) ? $dmMetadataCacheDriver['port'] : '%doctrine.odm.mongodb.cache.memcache_port%';
  238. $memcacheInstanceClass = isset($dmMetadataCacheDriver['instance-class']) ? $dmMetadataCacheDriver['instance-class'] : (isset($dmMetadataCacheDriver['instance_class']) ? $dmMetadataCacheDriver['instance_class'] : '%doctrine.odm.mongodb.cache.memcache_instance_class%');
  239. $memcacheInstance = new Definition($memcacheInstanceClass);
  240. $memcacheInstance->addMethodCall('connect', array($memcacheHost, $memcachePort));
  241. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_memcache_instance', $documentManager['name']), $memcacheInstance);
  242. $cacheDef->addMethodCall('setMemcache', array(new Reference(sprintf('doctrine.odm.mongodb.%s_memcache_instance', $documentManager['name']))));
  243. } else {
  244. $cacheDef = new Definition(sprintf('%%doctrine.odm.mongodb.cache.%s_class%%', $type));
  245. }
  246. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_metadata_cache', $documentManager['name']), $cacheDef);
  247. }
  248. /**
  249. * Loads the configured connections.
  250. *
  251. * @param array $config An array of configuration settings
  252. * @param ContainerBuilder $container A ContainerBuilder instance
  253. */
  254. protected function loadConnections(array $config, ContainerBuilder $container)
  255. {
  256. $connections = $this->getConnections($config, $container);
  257. foreach ($connections as $name => $connection) {
  258. $odmConnArgs = array(
  259. isset($connection['server']) ? $connection['server'] : null,
  260. isset($connection['options']) ? $connection['options'] : array(),
  261. new Reference(sprintf('doctrine.odm.mongodb.%s_configuration', $name))
  262. );
  263. $odmConnDef = new Definition('%doctrine.odm.mongodb.connection_class%', $odmConnArgs);
  264. $container->setDefinition(sprintf('doctrine.odm.mongodb.%s_connection', $name), $odmConnDef);
  265. }
  266. }
  267. /**
  268. * Gets the configured connections.
  269. *
  270. * @param array $config An array of configuration settings
  271. * @param ContainerBuilder $container A ContainerBuilder instance
  272. */
  273. protected function getConnections(array $config, ContainerBuilder $container)
  274. {
  275. $defaultConnection = $container->getParameter('doctrine.odm.mongodb.default_connection');
  276. $connections = array();
  277. if (isset($config['connections'])) {
  278. $configConnections = $config['connections'];
  279. if (isset($config['connections']['connection']) && isset($config['connections']['connection'][0])) {
  280. // Multiple connections
  281. $configConnections = $config['connections']['connection'];
  282. }
  283. foreach ($configConnections as $name => $connection) {
  284. $connections[isset($connection['id']) ? $connection['id'] : $name] = $connection;
  285. }
  286. } else {
  287. $connections = array($defaultConnection => $config);
  288. }
  289. return $connections;
  290. }
  291. /**
  292. * Loads an ODM document managers bundle mapping information.
  293. *
  294. * There are two distinct configuration possibilities for mapping information:
  295. *
  296. * 1. Specifiy a bundle and optionally details where the entity and mapping information reside.
  297. * 2. Specifiy an arbitrary mapping location.
  298. *
  299. * @example
  300. *
  301. * doctrine.orm:
  302. * mappings:
  303. * MyBundle1: ~
  304. * MyBundle2: yml
  305. * MyBundle3: { type: annotation, dir: Documents/ }
  306. * MyBundle4: { type: xml, dir: Resources/config/doctrine/mapping }
  307. * MyBundle5:
  308. * type: yml
  309. * dir: [bundle-mappings1/, bundle-mappings2/]
  310. * alias: BundleAlias
  311. * arbitrary_key:
  312. * type: xml
  313. * dir: %kernel.dir%/../src/vendor/DoctrineExtensions/lib/DoctrineExtensions/Documents
  314. * prefix: DoctrineExtensions\Documents\
  315. * alias: DExt
  316. *
  317. * In the case of bundles everything is really optional (which leads to autodetection for this bundle) but
  318. * in the mappings key everything except alias is a required argument.
  319. *
  320. * @param array $documentManager A configured ODM entity manager.
  321. * @param Definition A Definition instance
  322. * @param ContainerBuilder $container A ContainerBuilder instance
  323. */
  324. protected function loadDocumentManagerBundlesMappingInformation(array $documentManager, Definition $odmConfigDef, ContainerBuilder $container)
  325. {
  326. // reset state of drivers and alias map. They are only used by this methods and children.
  327. $this->drivers = array();
  328. $this->aliasMap = array();
  329. $this->loadMappingInformation($documentManager, $container);
  330. $this->registerMappingDrivers($documentManager, $container);
  331. if ($odmConfigDef->hasMethodCall('setDocumentNamespaces')) {
  332. // TODO: Can we make a method out of it on Definition? replaceMethodArguments() or something.
  333. $calls = $odmConfigDef->getMethodCalls();
  334. foreach ($calls AS $call) {
  335. if ($call[0] == 'setDocumentNamespaces') {
  336. $this->aliasMap = array_merge($call[1][0], $this->aliasMap);
  337. }
  338. }
  339. $method = $odmConfigDef->removeMethodCall('setDocumentNamespaces');
  340. }
  341. $odmConfigDef->addMethodCall('setDocumentNamespaces', array($this->aliasMap));
  342. }
  343. protected function getObjectManagerElementName($name)
  344. {
  345. return 'doctrine.odm.mongodb.' . $name;
  346. }
  347. protected function getMappingObjectDefaultName()
  348. {
  349. return 'Document';
  350. }
  351. protected function getMappingResourceConfigDirectory()
  352. {
  353. return 'Resources/config/doctrine/metadata/mongodb';
  354. }
  355. /**
  356. * Returns the namespace to be used for this extension (XML namespace).
  357. *
  358. * @return string The XML namespace
  359. */
  360. public function getNamespace()
  361. {
  362. return 'http://www.symfony-project.org/schema/dic/doctrine/odm/mongodb';
  363. }
  364. /**
  365. * @return string
  366. */
  367. public function getXsdValidationBasePath()
  368. {
  369. return __DIR__.'/../Resources/config/schema';
  370. }
  371. /**
  372. * Returns the recommended alias to use in XML.
  373. *
  374. * This alias is also the mandatory prefix to use when using YAML.
  375. *
  376. * @return string The alias
  377. */
  378. public function getAlias()
  379. {
  380. return 'doctrine_odm';
  381. }
  382. }