PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/protected/extensions/doctrine/components/DoctrineComponent.php

https://bitbucket.org/NordLabs/yiidoctrine
PHP | 327 lines | 213 code | 42 blank | 72 comment | 27 complexity | e55e43c183c42d69563c8cfef3e2e1fc MD5 | raw file
Possible License(s): BSD-2-Clause, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. use Doctrine\DBAL\Connection;
  3. use Doctrine\DBAL\DriverManager;
  4. use Doctrine\ORM\Configuration;
  5. use Doctrine\ORM\EntityManager;
  6. use Doctrine\Common\Cache\AbstractCache;
  7. use Doctrine\Common\Cache\MemcacheCache;
  8. use Doctrine\Common\ClassLoader;
  9. use Doctrine\Common\Annotations\AnnotationReader;
  10. use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
  11. // Register vendor namespaces.
  12. Yii::setPathOfAlias('Doctrine', __DIR__.'/../vendors/Doctrine');
  13. Yii::setPathOfAlias('Symfony', __DIR__.'/../vendors/Symfony');
  14. // todo: use Yii's cache component instead of a custom one.
  15. class DoctrineComponent extends CApplicationComponent {
  16. /**
  17. * List of dbal configurations. Each configuration has the following options
  18. * @link http://www.doctrine-project.org/docs/dbal/2.0/en/reference/configuration.html
  19. * See the Doctrine Documentation for an explanation of connection parameters
  20. * @var array
  21. */
  22. public $dbal;
  23. /**
  24. * List of cache configurations. Each with the following options
  25. * <ul>
  26. * <li>driver - (string) the driver e.g. ApcCache, MemcacheCache</li>
  27. * <li>namespace - (string) the cache namespace</li>
  28. * <li>servers - (array) used for memcache</li>
  29. * </ul>
  30. * @var array
  31. */
  32. public $cache;
  33. /**
  34. * List of entity manager configurations. Each with the following options
  35. * <ul>
  36. * <li>connection - (string) the dbal config name</li>
  37. * <li>mappingDriver - (string) [AnnotationDriver, YamlDriver, XmlDriver]</li>
  38. * <li>mappingPaths - (array) An array of paths to find mapping information</li>
  39. * <li>mappingDriverOptions - (array) Additional mapping driver options
  40. * defined in and array and make reference to each of the drivers set
  41. * methods</li>
  42. * <li>metadataCache - (string) the cache configuration for metadata</li>
  43. * <li>queryCache - (string) the cache configuration for query conversions</li>
  44. * <li>resultCache - (string) the cache configuration for results</li>
  45. * <li>proxyDir - (string)the directory location for proxy classes</li>
  46. * <li>proxyNamespace - (string) the proxy namespace</li>
  47. * <li>entityNamespaces - (array) entity namespaces</li>
  48. * <li>autoGenerateProxyClasses - (bool) true false</li>
  49. * </ul>
  50. * @var array
  51. */
  52. public $entityManager;
  53. /**
  54. * Cached component instances
  55. * @var array
  56. */
  57. private $_cache;
  58. /**
  59. * Get an instance of a DBAL Connection
  60. * @param string $name the connection name
  61. * @return Doctrine\DBAL\Connection
  62. */
  63. public function getConnection($name = 'default') {
  64. if (isset($this->_cache['dbal'][$name]) && $this->_cache['dbal'][$name] instanceof Connection) {
  65. return $this->_cache['dbal'][$name];
  66. }
  67. $config = $this->dbal[$name];
  68. $conn = DriverManager::getConnection($config, $this->_getDBALConfiguration($config), $this->_getEventManager($config));
  69. $this->_cache['dbal'][$name] = $conn;
  70. return $conn;
  71. }
  72. /**
  73. * Returns a cache instance. Drivers can be specified by their fully qualified name
  74. * e.g. Doctrine\Common\Cache\ArrayCache or by their short name e.g. ArrayCache.
  75. * If driver class is a custom implementation, it must extend from Doctrine\Common\Cache\AbstractCache.
  76. * @param string $name the cache name
  77. * @return Doctrine\Common\Cache\AbstractCache
  78. * @throws CException
  79. */
  80. public function getCache($name = 'default') {
  81. if (isset($this->_cache['cache'][$name]) && $this->_cache['cache'][$name] instanceof AbstractCache) {
  82. return $this->_cache['cache'][$name];
  83. }
  84. if (!isset($this->cache[$name])) {
  85. throw new \CException('Unknown cache configuration "'.$name.'"');
  86. }
  87. $doctrineDrivers = array(
  88. 'ApcCache' => 'Doctrine\Common\Cache\ApcCache',
  89. 'ArrayCache' => 'Doctrine\Common\Cache\ArrayCache',
  90. 'MemcacheCache' => 'Doctrine\Common\Cache\MemcacheCache',
  91. 'XcacheCache' => 'Doctrine\Common\Cache\XcacheCache',
  92. );
  93. $config = $this->cache[$name];
  94. if (array_key_exists($config['driver'], $doctrineDrivers)) {
  95. $driver = new $doctrineDrivers[$config['driver']];
  96. } else {
  97. if (in_array($config['driver'], $doctrineDrivers)) {
  98. $driver = new $config['driver'];
  99. } else {
  100. if (isset($config['driver'])) {
  101. $driver = new $config['driver'];
  102. if (!$driver instanceof AbstractCache) {
  103. throw new \CException('Cache driver must inherit from AbstractCache');
  104. }
  105. }
  106. }
  107. }
  108. if (!isset($driver)) {
  109. throw new \CException('Unknown cache configuration "'.$name.'"');
  110. }
  111. if (isset($config['namespace'])) {
  112. $driver->setNamespace($config['namespace']);
  113. }
  114. if (method_exists($driver, 'initialize')) {
  115. $driver->initialize($config);
  116. }
  117. if ($driver instanceof MemcacheCache) {
  118. $defaultServer = array(
  119. 'host' => 'localhost',
  120. 'port' => 11211,
  121. 'persistent' => true,
  122. 'weight' => 1,
  123. 'timeout' => 1,
  124. 'retryInterval' => 15,
  125. 'status' => true,
  126. );
  127. $memcache = new \Memcache();
  128. if (isset($config['servers'])) {
  129. foreach ($config['servers'] as $server) {
  130. $server = array_replace_recursive($defaultServer, $server);
  131. $memcache->addServer($server['host'], $server['port'], $server['persistent'], $server['weight'], $server['timeout'],
  132. $server['retryInterval'], $server['status']);
  133. }
  134. } else {
  135. $memcache->addServer($defaultServer['host'], $defaultServer['port'], $defaultServer['persistent'], $defaultServer['weight'],
  136. $defaultServer['timeout'], $defaultServer['retryInterval'], $defaultServer['status']);
  137. }
  138. $driver->setMemcache($memcache);
  139. }
  140. $this->_cache['cache'][$name] = $driver;
  141. return $driver;
  142. }
  143. /**
  144. * Returns an entity manager
  145. *
  146. * @param string $name the entity manager configuration name
  147. *
  148. * @return Doctrine\ORM\EntityManager
  149. * @throws CException
  150. */
  151. public function getEntityManager($name = 'default') {
  152. if (isset($this->_cache['em'][$name])) {
  153. return $this->_cache['em'][$name];
  154. }
  155. if (!isset($this->entityManager[$name])) {
  156. throw new \CException('Unknown entity manager configuration "'.$name.'"');
  157. }
  158. $options = $this->entityManager[$name];
  159. $conn = $this->getConnection($options['connection']);
  160. $config = new Configuration();
  161. unset($options['connection']);
  162. $driver = $this->_getMappingDriver($options);
  163. $config->setMetadataDriverImpl($driver);
  164. // set metadata cache
  165. if (isset($options['metadataCache'])) {
  166. $config->setMetadataCacheImpl($this->getCache($options['metadataCache']));
  167. unset($options['metadataCache']);
  168. }
  169. // set query cache
  170. if (isset($options['queryCache'])) {
  171. $config->setQueryCacheImpl($this->getCache($options['queryCache']));
  172. unset($options['queryCache']);
  173. }
  174. // set result cache
  175. if (isset($options['resultCache'])) {
  176. $config->setResultCacheImpl($this->getCache($options['resultCache']));
  177. unset($options['resultCache']);
  178. }
  179. $options['proxyDir'] = \Yii::getPathOfAlias($options['proxyDir']);
  180. // loop through setters of remaining options
  181. foreach ($options as $key => $value) {
  182. $method = 'set' . ucfirst($key);
  183. if (method_exists($config, $method)) {
  184. $config->{$method}($value);
  185. }
  186. }
  187. $em = EntityManager::create($conn, $config);
  188. $this->_cache['em'][$name] = $em;
  189. return $em;
  190. }
  191. /**
  192. * Take the configuration and return a mapping driver
  193. * @param array &$config the driver options
  194. * @return Doctrine\ORM\Mapping\Driver\Driver
  195. */
  196. private function _getMappingDriver(array & $config) {
  197. $drivers = array(
  198. 'XmlDriver' => 'Doctrine\ORM\Mapping\Driver\XmlDriver',
  199. 'YamlDriver' => 'Doctrine\ORM\Mapping\Driver\YamlDriver',
  200. );
  201. if (is_array($config['mappingPaths'])) {
  202. foreach ($config['mappingPaths'] as $index => $path) {
  203. $config['mappingPaths'][$index] = \Yii::getPathOfAlias($path);
  204. }
  205. } else {
  206. $config['mappingPaths'] = \Yii::getPathOfAlias($config['mappingPaths']);
  207. }
  208. // set default annotation driver
  209. // todo: fix AnnotationDriver, currently it throws an exception.
  210. if (!array_key_exists($config['mappingDriver'], $drivers) || $config['mappingDriver'] === 'AnnotationDriver') {
  211. $reader = new AnnotationReader();
  212. $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
  213. $driver = new AnnotationDriver($reader, $config['mappingPaths']);
  214. unset($config['mappingDriver']);
  215. unset($config['mappingPaths']);
  216. return $driver;
  217. }
  218. $mappingClass = $drivers[$config['mappingDriver']];
  219. $driver = new $mappingClass($config['mappingPaths']);
  220. if (isset($config['mappingDriverOptions']) === true) {
  221. foreach ($config['mappingDriverOptions'] as $key => $value) {
  222. $method = 'set' . ucfirst($key);
  223. if (method_exists($driver, $method) === true) {
  224. $driver->{$method}($value);
  225. }
  226. }
  227. unset($config['mappingDriverOptions']);
  228. }
  229. unset($config['mappingDriver']);
  230. unset($config['mappingDriverPaths']);
  231. return $driver;
  232. }
  233. /**
  234. * Get an event manager configuration
  235. * @param array $config the configuration
  236. * @return Doctrine\Common\EventManager|null
  237. */
  238. private function _getEventManager(array $config = array()) {
  239. if (!isset($config['eventManagerClass'])) {
  240. return null;
  241. }
  242. if (!isset($this->_cache['eventManager'])) {
  243. $eventManagerClass = $config['eventManagerClass'];
  244. $this->_cache['eventManager'] = new $eventManagerClass();
  245. }
  246. if (isset($config['eventSubscribers'])) {
  247. foreach ($config['eventSubscribers'] as $subscriber) {
  248. $sub = new $subscriber();
  249. $this->_cache['eventManager']->addEventSubscriber($sub);
  250. }
  251. }
  252. return $this->_cache['eventManager'];
  253. }
  254. /**
  255. * Get a DBAL configuration
  256. * @param array $config the configuration
  257. * @return Doctrine\DBAL\Configuration|null
  258. */
  259. private function _getDBALConfiguration(array $config = array()) {
  260. if (!array_key_exists('configurationClass', $config)) {
  261. return null;
  262. }
  263. $configClass = $config['configurationClass'];
  264. $configuration = new $configClass();
  265. if (empty($config['sqlLoggerClass']) === false) {
  266. $sqlLoggerClass = $config['sqlLoggerClass'];
  267. $loggerClass = new $sqlLoggerClass();
  268. $configuration->setSQLLogger($loggerClass);
  269. }
  270. return $configuration;
  271. }
  272. }