MappedEventSubscriber.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. $cacheDriver = $objectManager->getMetadataFactory()->getCacheDriver();
  97. $cacheId = ExtensionMetadataFactory::getCacheId($class, $this->getNamespace());
  98. if ($cacheDriver && ($cached = $cacheDriver->fetch($cacheId)) !== false) {
  99. $this->configurations[$class] = $cached;
  100. $config = $cached;
  101. }
  102. }
  103. return $config;
  104. }
  105. /**
  106. * Get extended metadata mapping reader
  107. *
  108. * @param ObjectManager $objectManager
  109. * @return Gedmo\Mapping\ExtensionMetadataFactory
  110. */
  111. public function getExtensionMetadataFactory(ObjectManager $objectManager)
  112. {
  113. $oid = spl_object_hash($objectManager);
  114. if (!isset($this->extensionMetadataFactory[$oid])) {
  115. if (is_null($this->annotationReader)) {
  116. // create default annotation reader for extensions
  117. $this->annotationReader = $this->getDefaultAnnotationReader();
  118. }
  119. $this->extensionMetadataFactory[$oid] = new ExtensionMetadataFactory(
  120. $objectManager,
  121. $this->getNamespace(),
  122. $this->annotationReader
  123. );
  124. }
  125. return $this->extensionMetadataFactory[$oid];
  126. }
  127. /**
  128. * Set annotation reader class
  129. * since older doctrine versions do not provide an interface
  130. * it must provide these methods:
  131. * getClassAnnotations([reflectionClass])
  132. * getClassAnnotation([reflectionClass], [name])
  133. * getPropertyAnnotations([reflectionProperty])
  134. * getPropertyAnnotation([reflectionProperty], [name])
  135. *
  136. * @param object $reader - annotation reader class
  137. */
  138. public function setAnnotationReader($reader)
  139. {
  140. $this->annotationReader = $reader;
  141. }
  142. /**
  143. * Scans the objects for extended annotations
  144. * event subscribers must subscribe to loadClassMetadata event
  145. *
  146. * @param ObjectManager $objectManager
  147. * @param ClassMetadata $metadata
  148. * @return void
  149. */
  150. public function loadMetadataForObjectClass(ObjectManager $objectManager, ClassMetadata $metadata)
  151. {
  152. $factory = $this->getExtensionMetadataFactory($objectManager);
  153. $config = $factory->getExtensionMetadata($metadata);
  154. if ($config) {
  155. $this->configurations[$metadata->name] = $config;
  156. }
  157. }
  158. /**
  159. * Get the namespace of extension event subscriber.
  160. * used for cache id of extensions also to know where
  161. * to find Mapping drivers and event adapters
  162. *
  163. * @return string
  164. */
  165. abstract protected function getNamespace();
  166. /**
  167. * Create default annotation reader for extensions
  168. *
  169. * @return \Doctrine\Common\Annotations\AnnotationReader
  170. */
  171. private function getDefaultAnnotationReader()
  172. {
  173. if (null === $this->defaultAnnotationReader) {
  174. if (version_compare(\Doctrine\Common\Version::VERSION, '3.0.0-DEV', '>=')) {
  175. $reader = new \Doctrine\Common\Annotations\AnnotationReader();
  176. $reader->setAutoloadAnnotations(true);
  177. $reader = new \Doctrine\Common\Annotations\CachedReader($reader, new ArrayCache());
  178. } else if (version_compare(\Doctrine\Common\Version::VERSION, '2.1.0-BETA3-DEV', '>=')) {
  179. $reader = new \Doctrine\Common\Annotations\AnnotationReader();
  180. $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
  181. $reader->setIgnoreNotImportedAnnotations(true);
  182. $reader->setAnnotationNamespaceAlias('Gedmo\\Mapping\\Annotation\\', 'gedmo');
  183. $reader->setEnableParsePhpImports(false);
  184. $reader->setAutoloadAnnotations(true);
  185. $reader = new \Doctrine\Common\Annotations\CachedReader(
  186. new \Doctrine\Common\Annotations\IndexedReader($reader), new ArrayCache()
  187. );
  188. } else {
  189. $reader = new \Doctrine\Common\Annotations\AnnotationReader();
  190. $reader->setAutoloadAnnotations(true);
  191. $reader->setAnnotationNamespaceAlias('Gedmo\\Mapping\\Annotation\\', 'gedmo');
  192. $reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
  193. }
  194. $this->defaultAnnotationReader = $reader;
  195. }
  196. return $this->defaultAnnotationReader;
  197. }
  198. }