-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from Coosos/release-0.2.0
Release 0.2.0
- Loading branch information
Showing
16 changed files
with
521 additions
and
642 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
<?php | ||
|
||
namespace Coosos\VersionWorkflowBundle\Doctrine; | ||
|
||
use Coosos\VersionWorkflowBundle\Entity\VersionWorkflow; | ||
use Coosos\VersionWorkflowBundle\Model\VersionWorkflowTrait; | ||
use Doctrine\Common\Collections\ArrayCollection; | ||
use Doctrine\Common\Collections\Collection; | ||
use Doctrine\ORM\EntityManagerInterface; | ||
use Doctrine\ORM\PersistentCollection; | ||
use Doctrine\ORM\UnitOfWork; | ||
use ReflectionClass; | ||
use ReflectionException; | ||
|
||
/** | ||
* Class DetachEntity | ||
* This class use the reflection for access to UnitOfWork properties. | ||
* Because from version 2.8, detach method is deprecated | ||
* | ||
* @package Coosos\VersionWorkflowBundle\Doctrine | ||
* @author Remy Lescallier <[email protected]> | ||
*/ | ||
class DetachEntity | ||
{ | ||
/** | ||
* @var EntityManagerInterface | ||
*/ | ||
private $em; | ||
|
||
/** | ||
* DetachEntity constructor. | ||
* | ||
* @param EntityManagerInterface $em | ||
*/ | ||
public function __construct(EntityManagerInterface $em) | ||
{ | ||
$this->em = $em; | ||
} | ||
|
||
/** | ||
* Detach doctrine entity | ||
* | ||
* @param VersionWorkflowTrait $entity | ||
* @param UnitOfWork $unitOfWork | ||
* @param array $entitiesDetached | ||
* @param array $invokes | ||
* | ||
* @throws ReflectionException | ||
*/ | ||
public function detach($entity, UnitOfWork $unitOfWork, &$entitiesDetached = [], array $invokes = []) | ||
{ | ||
$visited = []; | ||
|
||
$this->doDetach($entity, $unitOfWork, $visited, $entitiesDetached, $invokes); | ||
} | ||
|
||
/** | ||
* Executes a detach operation on the given entity. | ||
* | ||
* @param object $entity | ||
* @param UnitOfWork $unitOfWork | ||
* @param array $visited | ||
* @param array $entitiesDetached | ||
* @param array $invokes | ||
* @param boolean $noCascade if true, don't cascade detach operation. | ||
* | ||
* @return void | ||
* @throws ReflectionException | ||
*/ | ||
private function doDetach( | ||
$entity, | ||
UnitOfWork $unitOfWork, | ||
array &$visited, | ||
array &$entitiesDetached, | ||
array $invokes, | ||
$noCascade = false | ||
) { | ||
if ($entity instanceof VersionWorkflow) { | ||
return; | ||
} | ||
|
||
$oid = spl_object_hash($entity); | ||
|
||
if (isset($visited[$oid])) { | ||
return; // Prevent infinite recursion | ||
} | ||
|
||
$visited[$oid] = $entity; // mark visited | ||
if ($unitOfWork->getEntityState($entity, UnitOfWork::STATE_DETACHED) === UnitOfWork::STATE_MANAGED) { | ||
if ($unitOfWork->isInIdentityMap($entity)) { | ||
$unitOfWork->removeFromIdentityMap($entity); | ||
} | ||
|
||
if (!$entity instanceof VersionWorkflow && | ||
isset($invokes['preUpdate']) && | ||
is_callable($invokes['preUpdate']) | ||
) { | ||
$invokes['preUpdate']($entity); | ||
} | ||
} | ||
|
||
$this->unsetEntity($entity, $unitOfWork, $entitiesDetached); | ||
|
||
if (!$noCascade) { | ||
$this->cascadeDetach($entity, $unitOfWork, $visited, $entitiesDetached, $invokes); | ||
} | ||
} | ||
|
||
/** | ||
* Use reflection for unset property data from unit of work class | ||
* | ||
* @param UnitOfWork $unitOfWork | ||
* @param string $property | ||
* @param string $oid | ||
* | ||
* @throws ReflectionException | ||
*/ | ||
public function unsetFromUnitOfWork(UnitOfWork $unitOfWork, string $property, string $oid) | ||
{ | ||
$filterCallback = function ($key) use ($oid) { | ||
return $key !== $oid; | ||
}; | ||
|
||
$propery = (new ReflectionClass($unitOfWork))->getProperty($property); | ||
$propery->setAccessible(true); | ||
|
||
$properyValueFiltered = array_filter($propery->getValue($unitOfWork), $filterCallback, ARRAY_FILTER_USE_KEY); | ||
$propery->setValue($unitOfWork, $properyValueFiltered); | ||
} | ||
|
||
/** | ||
* Cascades a detach operation to associated entities. | ||
* | ||
* @param object $entity | ||
* @param UnitOfWork $unitOfWork | ||
* @param array $visited | ||
* @param array $entitiesDetached | ||
* @param array $invokes | ||
* | ||
* @return void | ||
* @throws ReflectionException | ||
*/ | ||
private function cascadeDetach( | ||
$entity, | ||
UnitOfWork $unitOfWork, | ||
array &$visited, | ||
array &$entitiesDetached, | ||
array $invokes | ||
) { | ||
$class = $this->em->getClassMetadata(get_class($entity)); | ||
|
||
foreach ($class->associationMappings as $assoc) { | ||
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity); | ||
if ($relatedEntities instanceof PersistentCollection || | ||
$relatedEntities instanceof Collection || | ||
$relatedEntities instanceof ArrayCollection | ||
) { | ||
$this->unsetFromUnitOfWork($unitOfWork, 'collectionUpdates', spl_object_hash($relatedEntities)); | ||
$this->unsetFromUnitOfWork($unitOfWork, 'visitedCollections', spl_object_hash($relatedEntities)); | ||
} | ||
|
||
if ($relatedEntities instanceof PersistentCollection) { | ||
foreach ($relatedEntities->getDeleteDiff() as $entityDeleted) { | ||
$this->doDetach($entityDeleted, $unitOfWork, $visited, $entitiesDetached, $invokes); | ||
} | ||
|
||
$relatedEntities = $relatedEntities->unwrap(); | ||
} | ||
|
||
if ($relatedEntities instanceof Collection || is_array($relatedEntities)) { | ||
foreach ($relatedEntities as $relatedEntity) { | ||
$this->doDetach($relatedEntity, $unitOfWork, $visited, $entitiesDetached, $invokes); | ||
} | ||
} elseif ($relatedEntities !== null) { | ||
$this->doDetach($relatedEntities, $unitOfWork, $visited, $entitiesDetached, $invokes); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Unset entity | ||
* | ||
* @param mixed $entity | ||
* @param UnitOfWork $unitOfWork | ||
* @param array $entitiesDetached | ||
* | ||
* @throws ReflectionException | ||
*/ | ||
private function unsetEntity($entity, UnitOfWork $unitOfWork, array &$entitiesDetached) | ||
{ | ||
$oid = spl_object_hash($entity); | ||
|
||
$entitiesDetached[$oid] = true; | ||
$this->unsetFromUnitOfWork($unitOfWork, 'entityInsertions', $oid); | ||
$this->unsetFromUnitOfWork($unitOfWork, 'entityUpdates', $oid); | ||
$this->unsetFromUnitOfWork($unitOfWork, 'entityDeletions', $oid); | ||
$this->unsetFromUnitOfWork($unitOfWork, 'entityIdentifiers', $oid); | ||
$this->unsetFromUnitOfWork($unitOfWork, 'entityStates', $oid); | ||
$this->unsetFromUnitOfWork($unitOfWork, 'originalEntityData', $oid); | ||
$this->unsetFromUnitOfWork($unitOfWork, 'orphanRemovals', $oid); | ||
} | ||
} |
Oops, something went wrong.