ReferenceRepository.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\Common\DataFixtures;
  4. use BadMethodCallException;
  5. use Doctrine\ODM\PHPCR\DocumentManager as PhpcrDocumentManager;
  6. use Doctrine\Persistence\ObjectManager;
  7. use OutOfBoundsException;
  8. use function array_key_exists;
  9. use function array_keys;
  10. use function get_class;
  11. use function method_exists;
  12. use function sprintf;
  13. /**
  14. * ReferenceRepository class manages references for
  15. * fixtures in order to easily support the relations
  16. * between fixtures
  17. */
  18. class ReferenceRepository
  19. {
  20. /**
  21. * List of named references to the fixture objects
  22. * gathered during loads of fixtures
  23. *
  24. * @var array
  25. */
  26. private $references = [];
  27. /**
  28. * List of identifiers stored for references
  29. * in case if reference gets unmanaged, it will
  30. * use a proxy referenced by this identity
  31. *
  32. * @var array
  33. */
  34. private $identities = [];
  35. /**
  36. * Currently used object manager
  37. *
  38. * @var ObjectManager
  39. */
  40. private $manager;
  41. public function __construct(ObjectManager $manager)
  42. {
  43. $this->manager = $manager;
  44. }
  45. /**
  46. * Get identifier for a unit of work
  47. *
  48. * @param object $reference Reference object
  49. * @param object $uow Unit of work
  50. *
  51. * @return array
  52. */
  53. protected function getIdentifier($reference, $uow)
  54. {
  55. // In case Reference is not yet managed in UnitOfWork
  56. if (! $this->hasIdentifier($reference)) {
  57. $class = $this->manager->getClassMetadata(get_class($reference));
  58. return $class->getIdentifierValues($reference);
  59. }
  60. // Dealing with ORM UnitOfWork
  61. if (method_exists($uow, 'getEntityIdentifier')) {
  62. return $uow->getEntityIdentifier($reference);
  63. }
  64. // PHPCR ODM UnitOfWork
  65. if ($this->manager instanceof PhpcrDocumentManager) {
  66. return $uow->getDocumentId($reference);
  67. }
  68. // ODM UnitOfWork
  69. return $uow->getDocumentIdentifier($reference);
  70. }
  71. /**
  72. * Set the reference entry identified by $name
  73. * and referenced to $reference. If $name
  74. * already is set, it overrides it
  75. *
  76. * @param string $name
  77. * @param object $reference
  78. */
  79. public function setReference($name, $reference)
  80. {
  81. $this->references[$name] = $reference;
  82. if (! $this->hasIdentifier($reference)) {
  83. return;
  84. }
  85. // in case if reference is set after flush, store its identity
  86. $uow = $this->manager->getUnitOfWork();
  87. $this->identities[$name] = $this->getIdentifier($reference, $uow);
  88. }
  89. /**
  90. * Store the identifier of a reference
  91. *
  92. * @param string $name
  93. * @param mixed $identity
  94. */
  95. public function setReferenceIdentity($name, $identity)
  96. {
  97. $this->identities[$name] = $identity;
  98. }
  99. /**
  100. * Set the reference entry identified by $name
  101. * and referenced to managed $object. $name must
  102. * not be set yet
  103. *
  104. * Notice: in case if identifier is generated after
  105. * the record is inserted, be sure tu use this method
  106. * after $object is flushed
  107. *
  108. * @param string $name
  109. * @param object $object - managed object
  110. *
  111. * @return void
  112. *
  113. * @throws BadMethodCallException - if repository already has a reference by $name.
  114. */
  115. public function addReference($name, $object)
  116. {
  117. if (isset($this->references[$name])) {
  118. throw new BadMethodCallException(sprintf('Reference to "%s" already exists, use method setReference in order to override it', $name));
  119. }
  120. $this->setReference($name, $object);
  121. }
  122. /**
  123. * Loads an object using stored reference
  124. * named by $name
  125. *
  126. * @param string $name
  127. *
  128. * @return object
  129. *
  130. * @throws OutOfBoundsException - if repository does not exist.
  131. */
  132. public function getReference($name)
  133. {
  134. if (! $this->hasReference($name)) {
  135. throw new OutOfBoundsException(sprintf('Reference to "%s" does not exist', $name));
  136. }
  137. $reference = $this->references[$name];
  138. $meta = $this->manager->getClassMetadata(get_class($reference));
  139. if (! $this->manager->contains($reference) && isset($this->identities[$name])) {
  140. $reference = $this->manager->getReference(
  141. $meta->name,
  142. $this->identities[$name]
  143. );
  144. $this->references[$name] = $reference; // already in identity map
  145. }
  146. return $reference;
  147. }
  148. /**
  149. * Check if an object is stored using reference
  150. * named by $name
  151. *
  152. * @param string $name
  153. *
  154. * @return bool
  155. */
  156. public function hasReference($name)
  157. {
  158. return isset($this->references[$name]);
  159. }
  160. /**
  161. * Searches for reference names in the
  162. * list of stored references
  163. *
  164. * @param object $reference
  165. *
  166. * @return array
  167. */
  168. public function getReferenceNames($reference)
  169. {
  170. return array_keys($this->references, $reference, true);
  171. }
  172. /**
  173. * Checks if reference has identity stored
  174. *
  175. * @param string $name
  176. *
  177. * @return bool
  178. */
  179. public function hasIdentity($name)
  180. {
  181. return array_key_exists($name, $this->identities);
  182. }
  183. /**
  184. * Get all stored identities
  185. *
  186. * @return array
  187. */
  188. public function getIdentities()
  189. {
  190. return $this->identities;
  191. }
  192. /**
  193. * Get all stored references
  194. *
  195. * @return array
  196. */
  197. public function getReferences()
  198. {
  199. return $this->references;
  200. }
  201. /**
  202. * Get object manager
  203. *
  204. * @return ObjectManager
  205. */
  206. public function getManager()
  207. {
  208. return $this->manager;
  209. }
  210. /**
  211. * Checks if object has identifier already in unit of work.
  212. *
  213. * @param string $reference
  214. *
  215. * @return bool
  216. */
  217. private function hasIdentifier($reference)
  218. {
  219. // in case if reference is set after flush, store its identity
  220. $uow = $this->manager->getUnitOfWork();
  221. if ($this->manager instanceof PhpcrDocumentManager) {
  222. return $uow->contains($reference);
  223. }
  224. return $uow->isInIdentityMap($reference);
  225. }
  226. }