/library/App/Doctrine/Container.php

https://github.com/lboynton/zf-acl-navigation · PHP · 665 lines · 378 code · 108 blank · 179 comment · 38 complexity · 00721ab386ff53b65c08a94eec5595a4 MD5 · raw file

  1. <?php
  2. namespace App\Doctrine;
  3. use App\Exception,
  4. Doctrine\DBAL\Types\Type,
  5. Doctrine\Common\Annotations\AnnotationRegistry;
  6. /**
  7. * Doctrine Container class.
  8. *
  9. * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
  10. */
  11. class Container
  12. {
  13. /**
  14. * @var string Default DBAL Connection name.
  15. */
  16. public $defaultConnection = 'default';
  17. /**
  18. * @var default Default Cache Instance name.
  19. */
  20. public $defaultCacheInstance = 'default';
  21. /**
  22. * @var string Default ORM EntityManager name.
  23. */
  24. public $defaultEntityManager = 'default';
  25. /**
  26. * @var array Doctrine Context configuration.
  27. */
  28. private $configuration = array();
  29. /**
  30. * @var array Available DBAL Connections.
  31. */
  32. private $connections = array();
  33. /**
  34. * @var array Available Cache Instances.
  35. */
  36. private $cacheInstances = array();
  37. /**
  38. * @var array Available ORM EntityManagers.
  39. */
  40. private $entityManagers = array();
  41. /**
  42. * Constructor.
  43. *
  44. * @param array $config Doctrine Container configuration
  45. */
  46. public function __construct(array $config = array())
  47. {
  48. // Registering Class Loaders
  49. if (isset($config['classLoader'])) {
  50. $this->registerClassLoaders($config['classLoader']);
  51. }
  52. // Defining DBAL configuration
  53. $dbalConfig = $this->prepareDBALConfiguration($config);
  54. // Defining default DBAL Connection name
  55. $this->defaultConnection = $dbalConfig['defaultConnection'];
  56. // Defining Cache configuration
  57. $cacheConfig = array();
  58. if (isset($config['cache'])) {
  59. $cacheConfig = $this->prepareCacheInstanceConfiguration($config);
  60. // Defining default Cache instance
  61. $this->defaultCacheInstance = $cacheConfig['defaultCacheInstance'];
  62. }
  63. // Defining ORM configuration
  64. $ormConfig = array();
  65. if (isset($config['orm'])) {
  66. $ormConfig = $this->prepareORMConfiguration($config);
  67. // Defining default ORM EntityManager
  68. $this->defaultEntityManager = $ormConfig['defaultEntityManager'];
  69. }
  70. // Defining Doctrine Context configuration
  71. $this->configuration = array(
  72. 'dbal' => $dbalConfig['connections'],
  73. 'cache' => $cacheConfig['instances'],
  74. 'orm' => $ormConfig['entityManagers']
  75. );
  76. }
  77. /**
  78. * Register Doctrine Class Loaders
  79. *
  80. * @param array Doctrine Class Loader configuration
  81. */
  82. private function registerClassLoaders(array $config = array())
  83. {
  84. $classLoaderClass = $config['loaderClass'];
  85. $classLoaderFile = $config['loaderFile'];
  86. require_once $classLoaderFile;
  87. foreach ($config['loaders'] as $loaderItem) {
  88. $classLoader = new $classLoaderClass($loaderItem['namespace'], $loaderItem['includePath']);
  89. $classLoader->register();
  90. }
  91. }
  92. /**
  93. * Prepare DBAL Connections configurations.
  94. *
  95. * @param array $config Doctrine Container configuration
  96. *
  97. * @return array
  98. */
  99. private function prepareDBALConfiguration(array $config = array())
  100. {
  101. $dbalConfig = $config['dbal'];
  102. $defaultConnectionName = isset($dbalConfig['defaultConnection'])
  103. ? $dbalConfig['defaultConnection'] : $this->defaultConnection;
  104. unset($dbalConfig['defaultConnection']);
  105. $defaultConnection = array(
  106. 'eventManagerClass' => 'Doctrine\Common\EventManager',
  107. 'eventSubscribers' => array(),
  108. 'configurationClass' => 'Doctrine\DBAL\Configuration',
  109. 'sqlLoggerClass' => null,
  110. 'types' => array(),
  111. 'parameters' => array(
  112. 'wrapperClass' => null,
  113. 'driver' => 'pdo_mysql',
  114. 'host' => 'localhost',
  115. 'user' => 'root',
  116. 'password' => null,
  117. 'port' => null,
  118. 'driverOptions' => array()
  119. )
  120. );
  121. $connections = array();
  122. if (isset($dbalConfig['connections'])) {
  123. $configConnections = $dbalConfig['connections'];
  124. foreach ($configConnections as $name => $connection) {
  125. $name = isset($connection['id']) ? $connection['id'] : $name;
  126. $connections[$name] = array_replace_recursive($defaultConnection, $connection);
  127. }
  128. } else {
  129. $connections = array(
  130. $defaultConnectionName => array_replace_recursive($defaultConnection, $dbalConfig)
  131. );
  132. }
  133. return array(
  134. 'defaultConnection' => $defaultConnectionName,
  135. 'connections' => $connections
  136. );
  137. }
  138. /**
  139. * Prepare Cache Instances configurations.
  140. *
  141. * @param array $config Doctrine Container configuration
  142. *
  143. * @return array
  144. */
  145. private function prepareCacheInstanceConfiguration(array $config = array())
  146. {
  147. $cacheConfig = $config['cache'];
  148. $defaultCacheInstanceName = isset($cacheConfig['defaultCacheInstance'])
  149. ? $cacheConfig['defaultCacheInstance'] : $this->defaultCacheInstance;
  150. unset($cacheConfig['defaultCacheInstance']);
  151. $defaultCacheInstance = array(
  152. 'adapterClass' => 'Doctrine\Common\Cache\ArrayCache',
  153. 'namespace' => '',
  154. 'options' => array()
  155. );
  156. $instances = array();
  157. if (isset($cacheConfig['instances'])) {
  158. $configInstances = $cacheConfig['instances'];
  159. foreach ($configInstances as $name => $instance) {
  160. $name = isset($instance['id']) ? $instance['id'] : $name;
  161. $instances[$name] = array_replace_recursive($defaultCacheInstance, $instance);
  162. }
  163. } else {
  164. $instances = array(
  165. $defaultCacheInstanceName => array_replace_recursive($defaultCacheInstance, $cacheConfig)
  166. );
  167. }
  168. return array(
  169. 'defaultCacheInstance' => $defaultCacheInstanceName,
  170. 'instances' => $instances
  171. );
  172. }
  173. /**
  174. * Prepare ORM EntityManagers configurations.
  175. *
  176. * @param array $config Doctrine Container configuration
  177. *
  178. * @return array
  179. */
  180. private function prepareORMConfiguration(array $config = array())
  181. {
  182. $ormConfig = $config['orm'];
  183. $defaultEntityManagerName = isset($ormConfig['defaultEntityManager'])
  184. ? $ormConfig['defaultEntityManager'] : $this->defaultEntityManager;
  185. unset($ormConfig['defaultEntityManager']);
  186. $defaultEntityManager = array(
  187. 'entityManagerClass' => 'Doctrine\ORM\EntityManager',
  188. 'configurationClass' => 'Doctrine\ORM\Configuration',
  189. 'entityNamespaces' => array(),
  190. 'connection' => $this->defaultConnection,
  191. 'proxy' => array(
  192. 'autoGenerateClasses' => true,
  193. 'namespace' => 'Proxy',
  194. 'dir' => APPLICATION_PATH . '/../library/Proxy'
  195. ),
  196. 'queryCache' => $this->defaultCacheInstance,
  197. 'resultCache' => $this->defaultCacheInstance,
  198. 'metadataCache' => $this->defaultCacheInstance,
  199. 'metadataDrivers' => array(),
  200. 'DQLFunctions' => array(
  201. 'numeric' => array(),
  202. 'datetime' => array(),
  203. 'string' => array()
  204. )
  205. );
  206. $entityManagers = array();
  207. if (isset($ormConfig['entityManagers'])) {
  208. $configEntityManagers = $ormConfig['entityManagers'];
  209. foreach ($configEntityManagers as $name => $entityManager) {
  210. $name = isset($entityManager['id']) ? $entityManager['id'] : $name;
  211. $entityManagers[$name] = array_replace_recursive($defaultEntityManager, $entityManager);
  212. }
  213. } else {
  214. $entityManagers = array(
  215. $this->defaultConnection => array_replace_recursive($defaultEntityManager, $ormConfig)
  216. );
  217. }
  218. return array(
  219. 'defaultEntityManager' => $defaultEntityManagerName,
  220. 'entityManagers' => $entityManagers
  221. );
  222. }
  223. /**
  224. * Retrieve DBAL Connection based on its name. If no argument is provided,
  225. * it will attempt to get the default Connection.
  226. * If DBAL Connection name could not be found, NameNotFoundException is thrown.
  227. *
  228. * @throws Bisna\Application\Exception\NameNotFoundException
  229. *
  230. * @param string $connName Optional DBAL Connection name
  231. *
  232. * @return Doctrine\DBAL\Connection DBAL Connection
  233. */
  234. public function getConnection($connName = null)
  235. {
  236. $connName = $connName ?: $this->defaultConnection;
  237. // Check if DBAL Connection has not yet been initialized
  238. if ( ! isset($this->connections[$connName])) {
  239. // Check if DBAL Connection is configured
  240. if ( ! isset($this->configuration['dbal'][$connName])) {
  241. throw new Exception\NameNotFoundException("Unable to find Doctrine DBAL Connection '{$connName}'.");
  242. }
  243. $this->connections[$connName] = $this->startDBALConnection($this->configuration['dbal'][$connName]);
  244. unset($this->configuration['dbal'][$connName]);
  245. }
  246. return $this->connections[$connName];
  247. }
  248. /**
  249. * Retrieve Cache Instance based on its name. If no argument is provided,
  250. * it will attempt to get the default Instance.
  251. * If Cache Instance name could not be found, NameNotFoundException is thrown.
  252. *
  253. * @throws Bisna\Application\Exception\NameNotFoundException
  254. *
  255. * @param string $cacheName Optional Cache Instance name
  256. *
  257. * @return Doctrine\Common\Cache\Cache Cache Instance
  258. */
  259. public function getCacheInstance($cacheName = null)
  260. {
  261. $cacheName = $cacheName ?: $this->defaultCacheInstance;
  262. // Check if Cache Instance has not yet been initialized
  263. if ( ! isset($this->cacheInstances[$cacheName])) {
  264. // Check if Cache Instance is configured
  265. if ( ! isset($this->configuration['cache'][$cacheName])) {
  266. throw new Exception\NameNotFoundException("Unable to find Doctrine Cache Instance '{$cacheName}'.");
  267. }
  268. $this->cacheInstances[$cacheName] = $this->startCacheInstance($this->configuration['cache'][$cacheName]);
  269. unset($this->configuration['cache'][$cacheName]);
  270. }
  271. return $this->cacheInstances[$cacheName];
  272. }
  273. /**
  274. * Retrieve ORM EntityManager based on its name. If no argument provided,
  275. * it will attempt to get the default EntityManager.
  276. * If ORM EntityManager name could not be found, NameNotFoundException is thrown.
  277. *
  278. * @throws Bisna\Application\Exception\NameNotFoundException
  279. *
  280. * @param string $emName Optional ORM EntityManager name
  281. *
  282. * @return Doctrine\ORM\EntityManager ORM EntityManager
  283. */
  284. public function getEntityManager($emName = null)
  285. {
  286. $emName = $emName ?: $this->defaultEntityManager;
  287. // Check if ORM Entity Manager has not yet been initialized
  288. if ( ! isset($this->entityManagers[$emName])) {
  289. // Check if ORM EntityManager is configured
  290. if ( ! isset($this->configuration['orm'][$emName])) {
  291. throw new Exception\NameNotFoundException("Unable to find Doctrine ORM EntityManager '{$emName}'.");
  292. }
  293. $this->entityManagers[$emName] = $this->startORMEntityManager($this->configuration['orm'][$emName]);
  294. unset($this->configuration['orm'][$emName]);
  295. }
  296. return $this->entityManagers[$emName];
  297. }
  298. /**
  299. * Retrieves a list of names for all Entity Managers configured
  300. * and/or loaded
  301. *
  302. * @return array
  303. */
  304. public function getEntityManagerNames()
  305. {
  306. $configuredEMs = array_keys($this->configuration['orm']);
  307. $loadedEMs = array_keys($this->entityManagers);
  308. return array_merge($configuredEMs, $loadedEMs);
  309. }
  310. /**
  311. * Initialize the DBAL Connection.
  312. *
  313. * @param array $config DBAL Connection configuration.
  314. *
  315. * @return Doctrine\DBAL\Connection
  316. */
  317. private function startDBALConnection(array $config = array())
  318. {
  319. return \Doctrine\DBAL\DriverManager::getConnection(
  320. $config['parameters'],
  321. $this->startDBALConfiguration($config),
  322. $this->startDBALEventManager($config)
  323. );
  324. }
  325. /**
  326. * Initialize the DBAL Configuration.
  327. *
  328. * @param array $config DBAL Connection configuration.
  329. *
  330. * @return Doctrine\DBAL\Configuration
  331. */
  332. private function startDBALConfiguration(array $config = array())
  333. {
  334. $configClass = $config['configurationClass'];
  335. $configuration = new $configClass();
  336. // SQL Logger configuration
  337. if ( ! empty($config['sqlLoggerClass'])) {
  338. $sqlLoggerClass = $config['sqlLoggerClass'];
  339. $configuration->setSQLLogger(new $sqlLoggerClass());
  340. }
  341. //DBAL Types configuration
  342. $types = $config['types'];
  343. foreach ($types as $name => $className) {
  344. Type::addType($name, $className);
  345. }
  346. return $configuration;
  347. }
  348. /**
  349. * Initialize the EventManager.
  350. *
  351. * @param array $config DBAL Connection configuration.
  352. *
  353. * @return Doctrine\Common\EventManager
  354. */
  355. private function startDBALEventManager(array $config = array())
  356. {
  357. $eventManagerClass = $config['eventManagerClass'];
  358. $eventManager = new $eventManagerClass();
  359. // Event Subscribers configuration
  360. foreach ($config['eventSubscribers'] as $subscriber) {
  361. if ($subscriber) {
  362. $eventManager->addEventSubscriber(new $subscriber());
  363. }
  364. }
  365. return $eventManager;
  366. }
  367. /**
  368. * Initialize Cache Instance.
  369. *
  370. * @param array $config Cache Instance configuration.
  371. *
  372. * @return Doctrine\Common\Cache\Cache
  373. */
  374. private function startCacheInstance(array $config = array())
  375. {
  376. $adapterClass = $config['adapterClass'];
  377. $adapter = new $adapterClass();
  378. // Define namespace for cache
  379. if (isset($config['namespace']) && ! empty($config['namespace'])) {
  380. $adapter->setNamespace($config['namespace']);
  381. }
  382. if (method_exists($adapter, 'initialize')) {
  383. $adapter->initialize($config);
  384. } else if ($adapter instanceof \Doctrine\Common\Cache\MemcacheCache) {
  385. // Prevent stupid PHP error of missing extension (if other driver is being used)
  386. $memcacheClassName = 'Memcache';
  387. $memcache = new $memcacheClassName();
  388. // Default server configuration
  389. $defaultServer = array(
  390. 'host' => 'localhost',
  391. 'port' => 11211,
  392. 'persistent' => true,
  393. 'weight' => 1,
  394. 'timeout' => 1,
  395. 'retryInterval' => 15,
  396. 'status' => true
  397. );
  398. if (isset($config['options']['servers'])) {
  399. foreach ($config['options']['servers'] as $server) {
  400. $server = array_replace_recursive($defaultServer, $server);
  401. $memcache->addServer(
  402. $server['host'],
  403. $server['port'],
  404. $server['persistent'],
  405. $server['weight'],
  406. $server['timeout'],
  407. $server['retryInterval'],
  408. $server['status']
  409. );
  410. }
  411. }
  412. $adapter->setMemcache($memcache);
  413. }
  414. return $adapter;
  415. }
  416. /**
  417. * Initialize ORM EntityManager.
  418. *
  419. * @param array $config ORM EntityManager configuration.
  420. *
  421. * @return Doctrine\ORM\EntityManager
  422. */
  423. private function startORMEntityManager(array $config = array())
  424. {
  425. if (isset($config['entityManagerClass'])) {
  426. $entityManagerClass = $config['entityManagerClass'];
  427. } else {
  428. $entityManagerClass = '\Doctrine\ORM\EntityManager';
  429. }
  430. return $entityManagerClass::create(
  431. $this->getConnection($config['connection']),
  432. $this->startORMConfiguration($config)
  433. );
  434. }
  435. /**
  436. * Initialize ORM Configuration.
  437. *
  438. * @param array $config ORM EntityManager configuration.
  439. *
  440. * @return Doctrine\ORM\Configuration
  441. */
  442. private function startORMConfiguration(array $config = array())
  443. {
  444. $configClass = $config['configurationClass'];
  445. $configuration = new $configClass();
  446. $configuration = new \Doctrine\ORM\Configuration();
  447. // Entity Namespaces configuration
  448. foreach ($config['entityNamespaces'] as $alias => $namespace) {
  449. $configuration->addEntityNamespace($alias, $namespace);
  450. }
  451. // Proxy configuration
  452. $configuration->setAutoGenerateProxyClasses(
  453. ! in_array($config['proxy']['autoGenerateClasses'], array("0", "false", false))
  454. );
  455. $configuration->setProxyNamespace($config['proxy']['namespace']);
  456. $configuration->setProxyDir($config['proxy']['dir']);
  457. // Cache configuration
  458. $configuration->setMetadataCacheImpl($this->getCacheInstance($config['metadataCache']));
  459. $configuration->setResultCacheImpl($this->getCacheInstance($config['resultCache']));
  460. $configuration->setQueryCacheImpl($this->getCacheInstance($config['queryCache']));
  461. // Metadata configuration
  462. $configuration->setMetadataDriverImpl($this->startORMMetadata($config['metadataDrivers']));
  463. // DQL Functions configuration
  464. $dqlFunctions = $config['DQLFunctions'];
  465. foreach ($dqlFunctions['datetime'] as $name => $className) {
  466. $configuration->addCustomDatetimeFunction($name, $className);
  467. }
  468. foreach ($dqlFunctions['numeric'] as $name => $className) {
  469. $configuration->addCustomNumericFunction($name, $className);
  470. }
  471. foreach ($dqlFunctions['string'] as $name => $className) {
  472. $configuration->addCustomStringFunction($name, $className);
  473. }
  474. return $configuration;
  475. }
  476. /**
  477. * Initialize ORM Metadata drivers.
  478. *
  479. * @param array $config ORM Mapping drivers.
  480. *
  481. * @return Doctrine\ORM\Mapping\Driver\DriverChain
  482. */
  483. private function startORMMetadata(array $config = array())
  484. {
  485. $metadataDriver = new \Doctrine\ORM\Mapping\Driver\DriverChain();
  486. // Default metadata driver configuration
  487. $defaultMetadataDriver = array(
  488. 'adapterClass' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
  489. 'mappingNamespace' => '',
  490. 'mappingDirs' => array(),
  491. 'annotationReaderClass' => 'Doctrine\Common\Annotations\AnnotationReader',
  492. 'annotationReaderCache' => $this->defaultCacheInstance,
  493. 'annotationReaderNamespaces' => array()
  494. );
  495. // Setup AnnotationRegistry
  496. if (isset($config['annotationRegistry'])) {
  497. $this->startAnnotationRegistry($config['annotationRegistry']);
  498. }
  499. foreach ($config['drivers'] as $driver) {
  500. $driver = array_replace_recursive($defaultMetadataDriver, $driver);
  501. $reflClass = new \ReflectionClass($driver['adapterClass']);
  502. $nestedDriver = null;
  503. if (
  504. $reflClass->getName() == 'Doctrine\ORM\Mapping\Driver\AnnotationDriver' ||
  505. $reflClass->isSubclassOf('Doctrine\ORM\Mapping\Driver\AnnotationDriver')
  506. ) {
  507. $annotationReaderClass = $driver['annotationReaderClass'];
  508. $annotationReader = new $annotationReaderClass();
  509. if (method_exists($annotationReader, 'setDefaultAnnotationNamespace')) {
  510. $annotationReader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
  511. }
  512. if (method_exists($annotationReader, 'setAnnotationNamespaceAlias')) {
  513. $driver['annotationReaderNamespaces']['ORM'] = 'Doctrine\ORM\Mapping\\';
  514. foreach ($driver['annotationReaderNamespaces'] as $alias => $namespace) {
  515. $annotationReader->setAnnotationNamespaceAlias($namespace, $alias);
  516. }
  517. }
  518. $indexedReader = new \Doctrine\Common\Annotations\CachedReader(
  519. new \Doctrine\Common\Annotations\IndexedReader($annotationReader),
  520. $this->getCacheInstance($driver['annotationReaderCache'])
  521. );
  522. $nestedDriver = $reflClass->newInstance($indexedReader, $driver['mappingDirs']);
  523. } else {
  524. $nestedDriver = $reflClass->newInstance($driver['mappingDirs']);
  525. }
  526. $metadataDriver->addDriver($nestedDriver, $driver['mappingNamespace']);
  527. }
  528. if (($drivers = $metadataDriver->getDrivers()) && count($drivers) == 1) {
  529. reset($drivers);
  530. $metadataDriver = $drivers[key($drivers)];
  531. }
  532. return $metadataDriver;
  533. }
  534. /**
  535. * Initialize ORM Metatada Annotation Registry driver
  536. *
  537. * @param array $config ORM Annotation Registry configuration.
  538. */
  539. private function startAnnotationRegistry($config)
  540. {
  541. // Load annotations from Files
  542. if (isset($config['annotationFiles']) && is_array($config['annotationFiles'])) {
  543. foreach($config['annotationFiles'] as $file) {
  544. AnnotationRegistry::registerFile($file);
  545. }
  546. }
  547. // Load annotation namespaces
  548. if (isset($config['annotationNamespaces']) && is_array($config['annotationNamespaces'])) {
  549. foreach($config['annotationNamespaces'] as $annotationNamespace) {
  550. AnnotationRegistry::registerAutoloadNamespace(
  551. $annotationNamespace['namespace'],
  552. $annotationNamespace['includePath']
  553. );
  554. }
  555. }
  556. }
  557. }