MappedEventSubscriber.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. <?php
  2. namespace Gedmo\Mapping;
  3. use Doctrine\Common\Annotations\AnnotationReader;
  4. use Doctrine\Common\Annotations\CachedReader;
  5. use Doctrine\Common\Cache\ArrayCache;
  6. use Doctrine\Common\Annotations\Reader;
  7. use Gedmo\Mapping\ExtensionMetadataFactory;
  8. use Doctrine\Common\EventSubscriber;
  9. use Doctrine\Common\Persistence\ObjectManager;
  10. use Doctrine\Common\Persistence\Mapping\ClassMetadata;
  11. use Doctrine\Common\EventArgs;
  12. /**
  13. * This is extension of event subscriber class and is
  14. * used specifically for handling the extension metadata
  15. * mapping for extensions.
  16. *
  17. * It dries up some reusable code which is common for
  18. * all extensions who mapps additional metadata through
  19. * extended drivers
  20. *
  21. * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
  22. * @package Gedmo.Mapping
  23. * @subpackage MappedEventSubscriber
  24. * @link http://www.gediminasm.org
  25. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  26. */
  27. abstract class MappedEventSubscriber implements EventSubscriber
  28. {
  29. /**
  30. * List of cached object configurations
  31. *
  32. * @var array
  33. */
  34. protected $configurations = array();
  35. /**
  36. * ExtensionMetadataFactory used to read the extension
  37. * metadata through the extension drivers
  38. *
  39. * @var Gedmo\Mapping\ExtensionMetadataFactory
  40. */
  41. private $extensionMetadataFactory = array();
  42. /**
  43. * List of event adapters used for this listener
  44. *
  45. * @var array
  46. */
  47. private $adapters = array();
  48. /**
  49. * Custom annotation reader
  50. *
  51. * @var object
  52. */
  53. private $annotationReader;
  54. /**
  55. * @var \Doctrine\Common\Annotations\AnnotationReader
  56. */
  57. private $defaultAnnotationReader;
  58. /**
  59. * Get an event adapter to handle event specific
  60. * methods
  61. *
  62. * @param EventArgs $args
  63. * @throws \Gedmo\Exception\InvalidArgumentException - if event is not recognized
  64. * @return \Gedmo\Mapping\Event\AdapterInterface
  65. */
  66. protected function getEventAdapter(EventArgs $args)
  67. {
  68. $class = get_class($args);
  69. if (preg_match('@Doctrine\\\([^\\\]+)@', $class, $m) && in_array($m[1], array('ODM', 'ORM'))) {
  70. if (!isset($this->adapters[$m[1]])) {
  71. $adapterClass = $this->getNamespace() . '\\Mapping\\Event\\Adapter\\' . $m[1];
  72. if (!class_exists($adapterClass)) {
  73. $adapterClass = 'Gedmo\\Mapping\\Event\\Adapter\\'.$m[1];
  74. }
  75. $this->adapters[$m[1]] = new $adapterClass;
  76. }
  77. $this->adapters[$m[1]]->setEventArgs($args);
  78. return $this->adapters[$m[1]];
  79. } else {
  80. throw new \Gedmo\Exception\InvalidArgumentException('Event mapper does not support event arg class: '.$class);
  81. }
  82. }
  83. /**
  84. * Get the configuration for specific object class
  85. * if cache driver is present it scans it also
  86. *
  87. * @param ObjectManager $objectManager
  88. * @param string $class
  89. * @return array
  90. */
  91. public function getConfiguration(ObjectManager $objectManager, $class) {
  92. $config = array();
  93. if (isset($this->configurations[$class])) {
  94. $config = $this->configurations[$class];
  95. } else {
  96. $factory = $objectManager->getMetadataFactory();
  97. $cacheDriver = $factory->getCacheDriver();
  98. if ($cacheDriver) {
  99. $cacheId = ExtensionMetadataFactory::getCacheId($class, $this->getNamespace());
  100. if (($cached = $cacheDriver->fetch($cacheId)) !== false) {
  101. $this->configurations[$class] = $cached;
  102. $config = $cached;
  103. } else {
  104. // re-generate metadata on cache miss
  105. $this->loadMetadataForObjectClass($objectManager, $factory->getMetadataFor($class));
  106. if (isset($this->configurations[$class])) {
  107. $config = $this->configurations[$class];
  108. }
  109. }
  110. }
  111. }
  112. return $config;
  113. }
  114. /**
  115. * Get extended metadata mapping reader
  116. *
  117. * @param ObjectManager $objectManager
  118. * @return Gedmo\Mapping\ExtensionMetadataFactory
  119. */
  120. public function getExtensionMetadataFactory(ObjectManager $objectManager)
  121. {
  122. $oid = spl_object_hash($objectManager);
  123. if (!isset($this->extensionMetadataFactory[$oid])) {
  124. if (is_null($this->annotationReader)) {
  125. // create default annotation reader for extensions
  126. $this->annotationReader = $this->getDefaultAnnotationReader();
  127. }
  128. $this->extensionMetadataFactory[$oid] = new ExtensionMetadataFactory(
  129. $objectManager,
  130. $this->getNamespace(),
  131. $this->annotationReader
  132. );
  133. }
  134. return $this->extensionMetadataFactory[$oid];
  135. }
  136. /**
  137. * Set annotation reader class
  138. * since older doctrine versions do not provide an interface
  139. * it must provide these methods:
  140. * getClassAnnotations([reflectionClass])
  141. * getClassAnnotation([reflectionClass], [name])
  142. * getPropertyAnnotations([reflectionProperty])
  143. * getPropertyAnnotation([reflectionProperty], [name])
  144. *
  145. * @param object $reader - annotation reader class
  146. */
  147. public function setAnnotationReader($reader)
  148. {
  149. $this->annotationReader = $reader;
  150. }
  151. /**
  152. * Scans the objects for extended annotations
  153. * event subscribers must subscribe to loadClassMetadata event
  154. *
  155. * @param ObjectManager $objectManager
  156. * @param ClassMetadata $metadata
  157. * @return void
  158. */
  159. public function loadMetadataForObjectClass(ObjectManager $objectManager, ClassMetadata $metadata)
  160. {
  161. $factory = $this->getExtensionMetadataFactory($objectManager);
  162. $config = $factory->getExtensionMetadata($metadata);
  163. if ($config) {
  164. $this->configurations[$metadata->name] = $config;
  165. }
  166. }
  167. /**
  168. * Get the namespace of extension event subscriber.
  169. * used for cache id of extensions also to know where
  170. * to find Mapping drivers and event adapters
  171. *
  172. * @return string
  173. */
  174. abstract protected function getNamespace();
  175. /**
  176. * Create default annotation reader for extensions
  177. *
  178. * @return \Doctrine\Common\Annotations\AnnotationReader
  179. */
  180. private function getDefaultAnnotationReader()
  181. {
  182. if (null === $this->defaultAnnotationReader) {
  183. if (version_compare(\Doctrine\Common\Version::VERSION, '3.0.0-DEV', '>=')) {
  184. $reader = new \Doctrine\Common\Annotations\AnnotationReader();
  185. \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace(
  186. 'Gedmo\\Mapping\\Annotation',
  187. __DIR__ . '/../../'
  188. );
  189. $reader = new \Doctrine\Common\Annotations\CachedReader($reader, new ArrayCache());
  190. } else if (version_compare(\Doctrine\Common\Version::VERSION, '2.1.0RC4-DEV', '>=')) {
  191. $reader = new \Doctrine\Common\Annotations\AnnotationReader();
  192. \Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace(
  193. 'Gedmo\\Mapping\\Annotation',
  194. __DIR__ . '/../../'
  195. );
  196. $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
  197. $reader = new \Doctrine\Common\Annotations\CachedReader($reader, new ArrayCache());
  198. } else if (version_compare(\Doctrine\Common\Version::VERSION, '2.1.0-BETA3-DEV', '>=')) {
  199. $reader = new \Doctrine\Common\Annotations\AnnotationReader();
  200. $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
  201. $reader->setIgnoreNotImportedAnnotations(true);
  202. $reader->setAnnotationNamespaceAlias('Gedmo\\Mapping\\Annotation\\', 'gedmo');
  203. $reader->setEnableParsePhpImports(false);
  204. $reader->setAutoloadAnnotations(true);
  205. /*\Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace(
  206. 'Gedmo\\Mapping\\Annotation',
  207. __DIR__ . '/../../'
  208. );*/
  209. $reader = new \Doctrine\Common\Annotations\CachedReader(
  210. new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache()
  211. );
  212. } else {
  213. $reader = new \Doctrine\Common\Annotations\AnnotationReader();
  214. $reader->setAutoloadAnnotations(true);
  215. $reader->setAnnotationNamespaceAlias('Gedmo\\Mapping\\Annotation\\', 'gedmo');
  216. $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
  217. }
  218. $this->defaultAnnotationReader = $reader;
  219. }
  220. return $this->defaultAnnotationReader;
  221. }
  222. }