edmondscommerce /
doctrine-static-meta
| 1 | <?php declare(strict_types=1); |
||||
| 2 | |||||
| 3 | namespace EdmondsCommerce\DoctrineStaticMeta\Entity\Factory; |
||||
| 4 | |||||
| 5 | use Doctrine\Common\Collections\Collection; |
||||
| 6 | use Doctrine\Common\NotifyPropertyChanged; |
||||
| 7 | use Doctrine\ORM\EntityManagerInterface; |
||||
| 8 | use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper; |
||||
| 9 | use EdmondsCommerce\DoctrineStaticMeta\DoctrineStaticMeta; |
||||
| 10 | use EdmondsCommerce\DoctrineStaticMeta\Entity\DataTransferObjects\DtoFactory; |
||||
| 11 | use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Interfaces\PrimaryKey\IdFieldInterface; |
||||
| 12 | use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\AlwaysValidInterface; |
||||
| 13 | use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\DataTransferObjectInterface; |
||||
| 14 | use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\EntityInterface; |
||||
| 15 | use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\UsesPHPMetaDataInterface; |
||||
| 16 | use EdmondsCommerce\DoctrineStaticMeta\EntityManager\Mapping\GenericFactoryInterface; |
||||
| 17 | use ts\Reflection\ReflectionClass; |
||||
| 18 | |||||
| 19 | /** |
||||
| 20 | * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) |
||||
| 21 | * @SuppressWarnings(PHPMD.CouplingBetweenObjects) |
||||
| 22 | */ |
||||
| 23 | class EntityFactory implements GenericFactoryInterface, EntityFactoryInterface |
||||
| 24 | { |
||||
| 25 | /** |
||||
| 26 | * This array is used to track Entities that in the process of being created as part of a transaction |
||||
| 27 | * |
||||
| 28 | * @var array|EntityInterface[] |
||||
| 29 | */ |
||||
| 30 | private static $created = []; |
||||
| 31 | /** |
||||
| 32 | * @var NamespaceHelper |
||||
| 33 | */ |
||||
| 34 | protected $namespaceHelper; |
||||
| 35 | /** |
||||
| 36 | * @var EntityDependencyInjector |
||||
| 37 | */ |
||||
| 38 | protected $entityDependencyInjector; |
||||
| 39 | /** |
||||
| 40 | * @var EntityManagerInterface |
||||
| 41 | */ |
||||
| 42 | private $entityManager; |
||||
| 43 | /** |
||||
| 44 | * @var DtoFactory |
||||
| 45 | */ |
||||
| 46 | private $dtoFactory; |
||||
| 47 | /** |
||||
| 48 | * @var array|DataTransferObjectInterface[] |
||||
| 49 | */ |
||||
| 50 | private $dtosProcessed; |
||||
| 51 | |||||
| 52 | public function __construct( |
||||
| 53 | NamespaceHelper $namespaceHelper, |
||||
| 54 | EntityDependencyInjector $entityDependencyInjector, |
||||
| 55 | DtoFactory $dtoFactory |
||||
| 56 | ) { |
||||
| 57 | $this->namespaceHelper = $namespaceHelper; |
||||
| 58 | $this->entityDependencyInjector = $entityDependencyInjector; |
||||
| 59 | $this->dtoFactory = $dtoFactory; |
||||
| 60 | } |
||||
| 61 | |||||
| 62 | public function setEntityManager(EntityManagerInterface $entityManager): EntityFactoryInterface |
||||
| 63 | { |
||||
| 64 | $this->entityManager = $entityManager; |
||||
| 65 | |||||
| 66 | return $this; |
||||
| 67 | } |
||||
| 68 | |||||
| 69 | /** |
||||
| 70 | * Get an instance of the specific Entity Factory for a specified Entity |
||||
| 71 | * |
||||
| 72 | * Not type hinting the return because the whole point of this is to have an entity specific method, which we |
||||
| 73 | * can't hint for |
||||
| 74 | * |
||||
| 75 | * @param string $entityFqn |
||||
| 76 | * |
||||
| 77 | * @return mixed |
||||
| 78 | */ |
||||
| 79 | public function createFactoryForEntity(string $entityFqn) |
||||
| 80 | { |
||||
| 81 | $this->assertEntityManagerSet(); |
||||
| 82 | $factoryFqn = $this->namespaceHelper->getFactoryFqnFromEntityFqn($entityFqn); |
||||
| 83 | |||||
| 84 | return new $factoryFqn($this, $this->entityManager); |
||||
| 85 | } |
||||
| 86 | |||||
| 87 | private function assertEntityManagerSet(): void |
||||
| 88 | { |
||||
| 89 | if (!$this->entityManager instanceof EntityManagerInterface) { |
||||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||||
| 90 | throw new \RuntimeException( |
||||
| 91 | 'No EntityManager set, this must be set first using setEntityManager()' |
||||
| 92 | ); |
||||
| 93 | } |
||||
| 94 | } |
||||
| 95 | |||||
| 96 | public function getEntity(string $className) |
||||
| 97 | { |
||||
| 98 | return $this->create($className); |
||||
| 99 | } |
||||
| 100 | |||||
| 101 | /** |
||||
| 102 | * Build a new entity, optionally pass in a DTO to provide the data that should be used |
||||
| 103 | * |
||||
| 104 | * Optionally pass in an array of property=>value |
||||
| 105 | * |
||||
| 106 | * @param string $entityFqn |
||||
| 107 | * |
||||
| 108 | * @param DataTransferObjectInterface|null $dto |
||||
| 109 | * |
||||
| 110 | * @return mixed |
||||
| 111 | */ |
||||
| 112 | public function create(string $entityFqn, DataTransferObjectInterface $dto = null) |
||||
| 113 | { |
||||
| 114 | $this->assertEntityManagerSet(); |
||||
| 115 | |||||
| 116 | return $this->createEntity($entityFqn, $dto, true); |
||||
| 117 | } |
||||
| 118 | |||||
| 119 | /** |
||||
| 120 | * Create the Entity |
||||
| 121 | * |
||||
| 122 | * @param string $entityFqn |
||||
| 123 | * |
||||
| 124 | * @param DataTransferObjectInterface|null $dto |
||||
| 125 | * |
||||
| 126 | * @param bool $isRootEntity |
||||
| 127 | * |
||||
| 128 | * @return EntityInterface |
||||
| 129 | * @SuppressWarnings(PHPMD.BooleanArgumentFlag) |
||||
| 130 | */ |
||||
| 131 | private function createEntity( |
||||
| 132 | string $entityFqn, |
||||
| 133 | DataTransferObjectInterface $dto = null, |
||||
| 134 | $isRootEntity = true |
||||
| 135 | ): EntityInterface { |
||||
| 136 | if ($isRootEntity) { |
||||
| 137 | $this->dtosProcessed = []; |
||||
| 138 | } |
||||
| 139 | if (null === $dto) { |
||||
| 140 | $dto = $this->dtoFactory->createEmptyDtoFromEntityFqn($entityFqn); |
||||
| 141 | } |
||||
| 142 | $idString = (string)$dto->getId(); |
||||
| 143 | if (isset(self::$created[$idString])) { |
||||
| 144 | return self::$created[$idString]; |
||||
| 145 | } |
||||
| 146 | $entity = $this->getNewInstance($entityFqn, $dto->getId()); |
||||
| 147 | self::$created[$idString] = $entity; |
||||
| 148 | |||||
| 149 | $this->updateDto($entity, $dto); |
||||
| 150 | if ($isRootEntity) { |
||||
| 151 | $this->stopTransaction(); |
||||
| 152 | } |
||||
| 153 | $entity->update($dto); |
||||
| 154 | |||||
| 155 | return $entity; |
||||
| 156 | } |
||||
| 157 | |||||
| 158 | /** |
||||
| 159 | * Build a new instance, bypassing PPP protections so that we can call private methods and set the private |
||||
| 160 | * transaction property |
||||
| 161 | * |
||||
| 162 | * @param string $entityFqn |
||||
| 163 | * @param mixed $id |
||||
| 164 | * |
||||
| 165 | * @return EntityInterface |
||||
| 166 | */ |
||||
| 167 | private function getNewInstance(string $entityFqn, $id): EntityInterface |
||||
| 168 | { |
||||
| 169 | if (isset(self::$created[(string)$id])) { |
||||
| 170 | throw new \RuntimeException('Trying to get a new instance when one has already been created for this ID'); |
||||
| 171 | } |
||||
| 172 | $reflection = $this->getDoctrineStaticMetaForEntityFqn($entityFqn) |
||||
| 173 | ->getReflectionClass(); |
||||
| 174 | $entity = $reflection->newInstanceWithoutConstructor(); |
||||
| 175 | |||||
| 176 | $runInit = $reflection->getMethod(UsesPHPMetaDataInterface::METHOD_RUN_INIT); |
||||
| 177 | $runInit->setAccessible(true); |
||||
| 178 | $runInit->invoke($entity); |
||||
| 179 | |||||
| 180 | $transactionProperty = $reflection->getProperty(AlwaysValidInterface::CREATION_TRANSACTION_RUNNING_PROPERTY); |
||||
| 181 | $transactionProperty->setAccessible(true); |
||||
| 182 | $transactionProperty->setValue($entity, true); |
||||
| 183 | |||||
| 184 | $idSetter = $reflection->getMethod('set' . IdFieldInterface::PROP_ID); |
||||
| 185 | $idSetter->setAccessible(true); |
||||
| 186 | $idSetter->invoke($entity, $id); |
||||
| 187 | |||||
| 188 | if ($entity instanceof EntityInterface) { |
||||
| 189 | $this->initialiseEntity($entity); |
||||
| 190 | |||||
| 191 | $this->entityManager->persist($entity); |
||||
| 192 | |||||
| 193 | return $entity; |
||||
| 194 | } |
||||
| 195 | throw new \LogicException('Failed to create an instance of EntityInterface'); |
||||
| 196 | } |
||||
| 197 | |||||
| 198 | private function getDoctrineStaticMetaForEntityFqn(string $entityFqn): DoctrineStaticMeta |
||||
| 199 | { |
||||
| 200 | return $entityFqn::getDoctrineStaticMeta(); |
||||
| 201 | } |
||||
| 202 | |||||
| 203 | /** |
||||
| 204 | * Take an already instantiated Entity and perform the final initialisation steps |
||||
| 205 | * |
||||
| 206 | * @param EntityInterface $entity |
||||
| 207 | */ |
||||
| 208 | public function initialiseEntity(EntityInterface $entity): void |
||||
| 209 | { |
||||
| 210 | $entity->ensureMetaDataIsSet($this->entityManager); |
||||
| 211 | $this->addListenerToEntityIfRequired($entity); |
||||
| 212 | $this->entityDependencyInjector->injectEntityDependencies($entity); |
||||
| 213 | $debugInitMethod = $entity::getDoctrineStaticMeta() |
||||
| 214 | ->getReflectionClass() |
||||
| 215 | ->getMethod(UsesPHPMetaDataInterface::METHOD_DEBUG_INIT); |
||||
| 216 | $debugInitMethod->setAccessible(true); |
||||
| 217 | $debugInitMethod->invoke($entity); |
||||
| 218 | } |
||||
| 219 | |||||
| 220 | /** |
||||
| 221 | * Generally DSM Entities are using the Notify change tracking policy. |
||||
| 222 | * This ensures that they are fully set up for that |
||||
| 223 | * |
||||
| 224 | * @param EntityInterface $entity |
||||
| 225 | */ |
||||
| 226 | private function addListenerToEntityIfRequired(EntityInterface $entity): void |
||||
| 227 | { |
||||
| 228 | if (!$entity instanceof NotifyPropertyChanged) { |
||||
|
0 ignored issues
–
show
|
|||||
| 229 | return; |
||||
| 230 | } |
||||
| 231 | $listener = $this->entityManager->getUnitOfWork(); |
||||
| 232 | $entity->addPropertyChangedListener($listener); |
||||
| 233 | } |
||||
| 234 | |||||
| 235 | private function updateDto( |
||||
| 236 | EntityInterface $entity, |
||||
| 237 | DataTransferObjectInterface $dto |
||||
| 238 | ): void { |
||||
| 239 | $this->replaceNestedDtoWithEntityInstanceIfIdsMatch($dto, $entity); |
||||
| 240 | $this->replaceNestedDtosWithNewEntities($dto); |
||||
| 241 | $this->dtosProcessed[spl_object_hash($dto)] = true; |
||||
| 242 | } |
||||
| 243 | |||||
| 244 | /** |
||||
| 245 | * @param DataTransferObjectInterface $dto |
||||
| 246 | * @param EntityInterface $entity |
||||
| 247 | * @SuppressWarnings(PHPMD.NPathComplexity) |
||||
| 248 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
||||
| 249 | */ |
||||
| 250 | private function replaceNestedDtoWithEntityInstanceIfIdsMatch( |
||||
| 251 | DataTransferObjectInterface $dto, |
||||
| 252 | EntityInterface $entity |
||||
| 253 | ): void { |
||||
| 254 | $dtoHash = spl_object_hash($dto); |
||||
| 255 | if (isset($this->dtosProcessed[$dtoHash])) { |
||||
| 256 | return; |
||||
| 257 | } |
||||
| 258 | $this->dtosProcessed[$dtoHash] = true; |
||||
| 259 | $getters = $this->getGettersForDtosOrCollections($dto); |
||||
| 260 | if ([[], []] === $getters) { |
||||
| 261 | return; |
||||
| 262 | } |
||||
| 263 | list($dtoGetters, $collectionGetters) = array_values($getters); |
||||
| 264 | $entityFqn = \get_class($entity); |
||||
| 265 | foreach ($dtoGetters as $getter) { |
||||
| 266 | $propertyName = substr($getter, 3, -3); |
||||
| 267 | $issetAsEntityMethod = 'isset' . $propertyName . 'AsEntity'; |
||||
| 268 | if (true === $dto->$issetAsEntityMethod()) { |
||||
| 269 | continue; |
||||
| 270 | } |
||||
| 271 | |||||
| 272 | $got = $dto->$getter(); |
||||
| 273 | if (null === $got) { |
||||
| 274 | continue; |
||||
| 275 | } |
||||
| 276 | $gotHash = \spl_object_hash($got); |
||||
| 277 | if (isset($this->dtosProcessed[$gotHash])) { |
||||
| 278 | continue; |
||||
| 279 | } |
||||
| 280 | |||||
| 281 | if ($got instanceof DataTransferObjectInterface) { |
||||
| 282 | if ($got::getEntityFqn() === $entityFqn && $got->getId() === $entity->getId()) { |
||||
| 283 | $setter = 'set' . $propertyName; |
||||
| 284 | $dto->$setter($entity); |
||||
| 285 | continue; |
||||
| 286 | } |
||||
| 287 | $this->replaceNestedDtoWithEntityInstanceIfIdsMatch($got, $entity); |
||||
| 288 | continue; |
||||
| 289 | } |
||||
| 290 | |||||
| 291 | throw new \LogicException('Unexpected got item ' . \get_class($got)); |
||||
| 292 | } |
||||
| 293 | foreach ($collectionGetters as $getter) { |
||||
| 294 | $got = $dto->$getter(); |
||||
| 295 | if (false === ($got instanceof Collection)) { |
||||
| 296 | continue; |
||||
| 297 | } |
||||
| 298 | foreach ($got as $key => $gotItem) { |
||||
| 299 | if (false === ($gotItem instanceof DataTransferObjectInterface)) { |
||||
| 300 | continue; |
||||
| 301 | } |
||||
| 302 | if ($gotItem::getEntityFqn() === $entityFqn && $gotItem->getId() === $entity->getId()) { |
||||
| 303 | $got->set($key, $entity); |
||||
| 304 | continue; |
||||
| 305 | } |
||||
| 306 | $this->replaceNestedDtoWithEntityInstanceIfIdsMatch($gotItem, $entity); |
||||
| 307 | } |
||||
| 308 | } |
||||
| 309 | } |
||||
| 310 | |||||
| 311 | private function getGettersForDtosOrCollections(DataTransferObjectInterface $dto): array |
||||
| 312 | { |
||||
| 313 | $dtoReflection = new ReflectionClass(\get_class($dto)); |
||||
| 314 | $dtoGetters = []; |
||||
| 315 | $collectionGetters = []; |
||||
| 316 | foreach ($dtoReflection->getMethods() as $method) { |
||||
| 317 | $methodName = $method->getName(); |
||||
| 318 | if (0 !== strpos($methodName, 'get')) { |
||||
| 319 | continue; |
||||
| 320 | } |
||||
| 321 | $returnType = $method->getReturnType(); |
||||
| 322 | if (null === $returnType) { |
||||
| 323 | continue; |
||||
| 324 | } |
||||
| 325 | $returnTypeName = $returnType->getName(); |
||||
| 326 | if (false === \ts\stringContains($returnTypeName, '\\')) { |
||||
| 327 | continue; |
||||
| 328 | } |
||||
| 329 | $returnTypeReflection = new ReflectionClass($returnTypeName); |
||||
| 330 | |||||
| 331 | if ($returnTypeReflection->implementsInterface(DataTransferObjectInterface::class)) { |
||||
| 332 | $dtoGetters[] = $methodName; |
||||
| 333 | continue; |
||||
| 334 | } |
||||
| 335 | if ($returnTypeReflection->implementsInterface(Collection::class)) { |
||||
| 336 | $collectionGetters[] = $methodName; |
||||
| 337 | continue; |
||||
| 338 | } |
||||
| 339 | } |
||||
| 340 | |||||
| 341 | return [$dtoGetters, $collectionGetters]; |
||||
| 342 | } |
||||
| 343 | |||||
| 344 | /** |
||||
| 345 | * @param DataTransferObjectInterface $dto |
||||
| 346 | * |
||||
| 347 | * @throws \ReflectionException |
||||
| 348 | * @SuppressWarnings(PHPMD.NPathComplexity) |
||||
| 349 | */ |
||||
| 350 | private function replaceNestedDtosWithNewEntities(DataTransferObjectInterface $dto) |
||||
| 351 | { |
||||
| 352 | $getters = $this->getGettersForDtosOrCollections($dto); |
||||
| 353 | if ([[], []] === $getters) { |
||||
| 354 | return; |
||||
| 355 | } |
||||
| 356 | list($dtoGetters, $collectionGetters) = array_values($getters); |
||||
| 357 | foreach ($dtoGetters as $getter) { |
||||
| 358 | $propertyName = substr($getter, 3, -3); |
||||
| 359 | $issetAsEntityMethod = 'isset' . $propertyName . 'AsEntity'; |
||||
| 360 | if (true === $dto->$issetAsEntityMethod()) { |
||||
| 361 | continue; |
||||
| 362 | } |
||||
| 363 | |||||
| 364 | $nestedDto = $dto->$getter(); |
||||
| 365 | if (null === $nestedDto) { |
||||
| 366 | continue; |
||||
| 367 | } |
||||
| 368 | $setter = 'set' . substr($getter, 3, -3); |
||||
| 369 | $dto->$setter($this->createEntity($nestedDto::getEntityFqn(), $nestedDto, false)); |
||||
| 370 | } |
||||
| 371 | foreach ($collectionGetters as $getter) { |
||||
| 372 | $nestedDto = $dto->$getter(); |
||||
| 373 | if (false === ($nestedDto instanceof Collection)) { |
||||
| 374 | continue; |
||||
| 375 | } |
||||
| 376 | $this->convertCollectionOfDtosToEntities($nestedDto); |
||||
| 377 | } |
||||
| 378 | } |
||||
| 379 | |||||
| 380 | /** |
||||
| 381 | * This will take an ArrayCollection of DTO objects and replace them with the Entities |
||||
| 382 | * |
||||
| 383 | * @param Collection $collection |
||||
| 384 | * |
||||
| 385 | * @throws \ReflectionException |
||||
| 386 | */ |
||||
| 387 | private function convertCollectionOfDtosToEntities(Collection $collection) |
||||
| 388 | { |
||||
| 389 | if (0 === $collection->count()) { |
||||
| 390 | return; |
||||
| 391 | } |
||||
| 392 | list($dtoFqn, $collectionEntityFqn) = $this->deriveDtoAndEntityFqnFromCollection($collection); |
||||
| 393 | |||||
| 394 | foreach ($collection as $key => $dto) { |
||||
| 395 | if ($dto instanceof $collectionEntityFqn) { |
||||
| 396 | continue; |
||||
| 397 | } |
||||
| 398 | if (false === \is_object($dto)) { |
||||
| 399 | throw new \InvalidArgumentException('Unexpected DTO value ' . |
||||
| 400 | \print_r($dto, true) . |
||||
| 401 | ', expected an instance of' . |
||||
| 402 | $dtoFqn); |
||||
| 403 | } |
||||
| 404 | if (false === ($dto instanceof DataTransferObjectInterface)) { |
||||
| 405 | throw new \InvalidArgumentException('Found none DTO item in collection, was instance of ' . |
||||
| 406 | \get_class($dto)); |
||||
| 407 | } |
||||
| 408 | if (false === ($dto instanceof $dtoFqn)) { |
||||
| 409 | throw new \InvalidArgumentException('Unexpected DTO ' . \get_class($dto) . ', expected ' . $dtoFqn); |
||||
| 410 | } |
||||
| 411 | $collection->set($key, $this->createEntity($collectionEntityFqn, $dto, false)); |
||||
| 412 | } |
||||
| 413 | } |
||||
| 414 | |||||
| 415 | /** |
||||
| 416 | * Loop through a collection and determine the DTO and Entity Fqn it contains |
||||
| 417 | * |
||||
| 418 | * @param Collection $collection |
||||
| 419 | * |
||||
| 420 | * @return array |
||||
| 421 | * @SuppressWarnings(PHPMD.NPathComplexity) |
||||
| 422 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
||||
| 423 | */ |
||||
| 424 | private function deriveDtoAndEntityFqnFromCollection(Collection $collection): array |
||||
| 425 | { |
||||
| 426 | if (0 === $collection->count()) { |
||||
| 427 | throw new \RuntimeException('Collection is empty'); |
||||
| 428 | } |
||||
| 429 | $dtoFqn = null; |
||||
| 430 | $collectionEntityFqn = null; |
||||
| 431 | foreach ($collection as $dto) { |
||||
| 432 | if ($dto instanceof EntityInterface) { |
||||
| 433 | $collectionEntityFqn = \get_class($dto); |
||||
| 434 | continue; |
||||
| 435 | } |
||||
| 436 | if (false === ($dto instanceof DataTransferObjectInterface)) { |
||||
| 437 | throw new \InvalidArgumentException( |
||||
| 438 | 'Found none DTO item in collection, was instance of ' . \get_class($dto) |
||||
| 439 | ); |
||||
| 440 | } |
||||
| 441 | if (null === $dtoFqn) { |
||||
| 442 | $dtoFqn = \get_class($dto); |
||||
| 443 | continue; |
||||
| 444 | } |
||||
| 445 | if (false === ($dto instanceof $dtoFqn)) { |
||||
| 446 | throw new \InvalidArgumentException( |
||||
| 447 | 'Mismatched collection, expecting dtoFqn ' . |
||||
| 448 | $dtoFqn . |
||||
| 449 | ' but found ' . |
||||
| 450 | \get_class($dto) |
||||
| 451 | ); |
||||
| 452 | } |
||||
| 453 | } |
||||
| 454 | if (null === $dtoFqn && null === $collectionEntityFqn) { |
||||
| 455 | throw new \RuntimeException('Failed deriving either the DTO or Entity FQN from the collection'); |
||||
| 456 | } |
||||
| 457 | if (null === $collectionEntityFqn) { |
||||
| 458 | $collectionEntityFqn = $this->namespaceHelper->getEntityFqnFromEntityDtoFqn($dtoFqn); |
||||
|
0 ignored issues
–
show
The function
EdmondsCommerce\Doctrine...tyFqnFromEntityDtoFqn() has been deprecated: please use the static method on the DTO directly
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 459 | } |
||||
| 460 | if (null === $dtoFqn) { |
||||
| 461 | $dtoFqn = $this->namespaceHelper->getEntityDtoFqnFromEntityFqn($collectionEntityFqn); |
||||
| 462 | } |
||||
| 463 | |||||
| 464 | return [$dtoFqn, $collectionEntityFqn]; |
||||
| 465 | } |
||||
| 466 | |||||
| 467 | /** |
||||
| 468 | * Loop through all created entities and reset the transaction running property to false, |
||||
| 469 | * then remove the list of created entities |
||||
| 470 | */ |
||||
| 471 | private function stopTransaction(): void |
||||
| 472 | { |
||||
| 473 | foreach (self::$created as $entity) { |
||||
| 474 | $transactionProperty = $entity::getDoctrineStaticMeta() |
||||
| 475 | ->getReflectionClass() |
||||
| 476 | ->getProperty(AlwaysValidInterface::CREATION_TRANSACTION_RUNNING_PROPERTY); |
||||
| 477 | $transactionProperty->setAccessible(true); |
||||
| 478 | $transactionProperty->setValue($entity, false); |
||||
| 479 | } |
||||
| 480 | //self::$created = []; |
||||
| 481 | $this->dtosProcessed = []; |
||||
| 482 | } |
||||
| 483 | } |
||||
| 484 |