Skip to content

Commit

Permalink
Merge pull request #3 from Coosos/release-0.2.0
Browse files Browse the repository at this point in the history
Release 0.2.0
  • Loading branch information
Coosos authored Apr 5, 2020
2 parents 44cf8d8 + e66b203 commit 6d66899
Show file tree
Hide file tree
Showing 16 changed files with 521 additions and 642 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# 0.2.0

* Move mapping serializer to own package (``coosos/jms-serializer-bidirectional-relation``)
* Fix array keys who an auto reset
* Necessary to add the annotation ``Coosos\BidirectionalRelation\Annotations\SerializerBidirectionalRelation``
to your root entity which will be serialized
* Fix array link entity to original
* DetachEntity (based on doctrine 2.7) class for recursive detach directly in properties of UnitOfWork
* Reorganize / Optimize code

# 0.1.4

* Update test
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,10 @@ If an old entity yet exists the same identifier, it will be replaced while keepi
* [Installation](docs/install.md)
* [Configuration](docs/config.md)
* [Basic usage](docs/usage.md)
* [Serializer](https://github.com/schmittjoh/serializer) : I propose directly to you to see the documentation of JMS.
* [Serializer](https://github.com/schmittjoh/serializer)
* [Use with doctrine](docs/doctrine.md)

## TODO

* Replace SingleStateMarkingStore by MethodMarkingStore
* Replace setInitialPlace by setInitialPlaces
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"symfony/http-kernel": "^4.2",
"symfony/property-info": "^4.2",
"doctrine/orm": "^2.6",
"jms/serializer-bundle": "^2.4||^3.0"
"jms/serializer-bundle": "^2.4||^3.0",
"coosos/jms-serializer-bidirectional-relation": "^1.0.0"
},
"require-dev": {
"edgedesign/phpqa": "^1.23",
Expand Down
7 changes: 6 additions & 1 deletion docs/usage.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# Usage

# Prepare your model
This bundle use ``coosos/jms-serializer-bidirectional-relation`` package, see the documentation for more configuration.

## Prepare your model

For your model to work with bundle, is necessary to use VersionWorkflowTrait.

/**
* @Coosos\BidirectionalRelation\Annotations\SerializerBidirectionalRelation()
*/
class News
{
use \Coosos\VersionWorkflowBundle\Model\VersionWorkflowTrait;
Expand Down
202 changes: 202 additions & 0 deletions src/Doctrine/DetachEntity.php
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);
}
}
Loading

0 comments on commit 6d66899

Please sign in to comment.