From c34b9ae60e83e1b47cd91de24ebb810c6855704b Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Wed, 25 Dec 2019 23:20:04 +0100 Subject: [PATCH] prefix Node with Tree, to make it explicit --- docs/tree.md | 16 ++++-- phpstan.neon | 4 +- .../TreeNodeInterface.php} | 4 +- src/EventSubscriber/TreeSubscriber.php | 4 +- src/Model/Tree/NodeTrait.php | 11 ---- ...hodsTrait.php => TreeNodeMethodsTrait.php} | 50 +++++++++---------- ...sTrait.php => TreeNodePropertiesTrait.php} | 8 +-- src/Model/Tree/TreeNodeTrait.php | 11 ++++ src/ORM/Tree/TreeTrait.php | 12 ++--- tests/Fixtures/Entity/TreeNodeEntity.php | 24 +++------ .../{Tree/NodeTest.php => TreeNodeTest.php} | 22 +++++--- upgrade/rector/doctrine-behaviors-20.yaml | 5 +- 12 files changed, 88 insertions(+), 83 deletions(-) rename src/Contract/{Model/Tree/NodeInterface.php => Entity/TreeNodeInterface.php} (96%) delete mode 100644 src/Model/Tree/NodeTrait.php rename src/Model/Tree/{NodeMethodsTrait.php => TreeNodeMethodsTrait.php} (80%) rename src/Model/Tree/{NodePropertiesTrait.php => TreeNodePropertiesTrait.php} (62%) create mode 100644 src/Model/Tree/TreeNodeTrait.php rename tests/ORM/{Tree/NodeTest.php => TreeNodeTest.php} (94%) diff --git a/docs/tree.md b/docs/tree.md index 278c0433..11c0df07 100644 --- a/docs/tree.md +++ b/docs/tree.md @@ -10,19 +10,25 @@ declare(strict_types=1); namespace App\Entity; use Doctrine\ORM\Mapping as ORM; -use Knp\DoctrineBehaviors\Contract\Model\Tree\NodeInterface; -use Knp\DoctrineBehaviors\Model\Tree\NodeTrait; +use Knp\DoctrineBehaviors\Contract\Entity\TreeNodeInterface; +use Knp\DoctrineBehaviors\Model\Tree\TreeNodeTrait; /** * @ORM\Entity */ -class Category implements NodeInterface +class Category implements TreeNodeInterface { - use NodeTrait; + use TreeNodeTrait; + + /** + * @ORM\Column(type="string") + * @var string + */ + private $name; public function __toString() : string { - return $this->...; + return (string) $this->name; } } ``` diff --git a/phpstan.neon b/phpstan.neon index d9957596..59b3c212 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -28,9 +28,9 @@ parameters: - '#Property Knp\\DoctrineBehaviors\\Tests\\Fixtures\\Entity\\GeocodableEntity\:\:\$location has no typehint specified#' # tests - - '#Offset 0 does not exist on array\|ArrayAccess\|null#' + - '#Offset 0 does not exist on array\|ArrayAccess\|null#' - - '#Cannot call method addChildNode\(\) on Knp\\DoctrineBehaviors\\Contract\\Model\\Tree\\NodeInterface\|null#' + - '#Cannot call method addChildNode\(\) on Knp\\DoctrineBehaviors\\Contract\\Entity\\TreeNodeInterface\|null#' # iterable - '#Parameter \#1 \$translations of method Knp\\DoctrineBehaviors\\Tests\\Fixtures\\Entity\\TranslatableEntity\:\:setTranslations\(\) expects Doctrine\\Common\\Collections\\Collection&iterable, array given#' diff --git a/src/Contract/Model/Tree/NodeInterface.php b/src/Contract/Entity/TreeNodeInterface.php similarity index 96% rename from src/Contract/Model/Tree/NodeInterface.php rename to src/Contract/Entity/TreeNodeInterface.php index 930d77ed..20d606a6 100644 --- a/src/Contract/Model/Tree/NodeInterface.php +++ b/src/Contract/Entity/TreeNodeInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Knp\DoctrineBehaviors\Contract\Model\Tree; +namespace Knp\DoctrineBehaviors\Contract\Entity; use Doctrine\Common\Collections\Collection; @@ -10,7 +10,7 @@ * Tree\Node defines a set of needed methods * to work with materialized path tree nodes */ -interface NodeInterface +interface TreeNodeInterface { public function __toString(): string; diff --git a/src/EventSubscriber/TreeSubscriber.php b/src/EventSubscriber/TreeSubscriber.php index d0b08d07..3037019e 100644 --- a/src/EventSubscriber/TreeSubscriber.php +++ b/src/EventSubscriber/TreeSubscriber.php @@ -7,7 +7,7 @@ use Doctrine\Common\EventSubscriber; use Doctrine\ORM\Event\LoadClassMetadataEventArgs; use Doctrine\ORM\Events; -use Knp\DoctrineBehaviors\Contract\Model\Tree\NodeInterface; +use Knp\DoctrineBehaviors\Contract\Entity\TreeNodeInterface; final class TreeSubscriber implements EventSubscriber { @@ -15,7 +15,7 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $loadClassMetadataE { $classMetadata = $loadClassMetadataEventArgs->getClassMetadata(); - if (! is_a($classMetadata->reflClass->getName(), NodeInterface::class, true)) { + if (! is_a($classMetadata->reflClass->getName(), TreeNodeInterface::class, true)) { return; } diff --git a/src/Model/Tree/NodeTrait.php b/src/Model/Tree/NodeTrait.php deleted file mode 100644 index 1654da27..00000000 --- a/src/Model/Tree/NodeTrait.php +++ /dev/null @@ -1,11 +0,0 @@ -childNodes; } - public function addChildNode(NodeInterface $node): void + public function addChildNode(TreeNodeInterface $treeNode): void { - $this->getChildNodes()->add($node); + $this->getChildNodes()->add($treeNode); } - public function isIndirectChildNodeOf(NodeInterface $node): bool + public function isIndirectChildNodeOf(TreeNodeInterface $treeNode): bool { - return $this->getRealMaterializedPath() !== $node->getRealMaterializedPath() - && strpos($this->getRealMaterializedPath(), $node->getRealMaterializedPath()) === 0; + return $this->getRealMaterializedPath() !== $treeNode->getRealMaterializedPath() + && strpos($this->getRealMaterializedPath(), $treeNode->getRealMaterializedPath()) === 0; } - public function isChildNodeOf(NodeInterface $node): bool + public function isChildNodeOf(TreeNodeInterface $treeNode): bool { - return $this->getParentMaterializedPath() === $node->getRealMaterializedPath(); + return $this->getParentMaterializedPath() === $treeNode->getRealMaterializedPath(); } - public function setChildNodeOf(?NodeInterface $node = null): void + public function setChildNodeOf(?TreeNodeInterface $treeNode = null): void { $id = $this->getNodeId(); if (empty($id)) { throw new LogicException('You must provide an id for this node if you want it to be part of a tree.'); } - $path = $node !== null - ? rtrim($node->getRealMaterializedPath(), static::getMaterializedPathSeparator()) + $path = $treeNode !== null + ? rtrim($treeNode->getRealMaterializedPath(), static::getMaterializedPathSeparator()) : static::getMaterializedPathSeparator(); $this->setMaterializedPath($path); @@ -122,30 +122,30 @@ public function setChildNodeOf(?NodeInterface $node = null): void $this->parentNode->getChildNodes()->removeElement($this); } - $this->parentNode = $node; + $this->parentNode = $treeNode; - if ($node !== null) { + if ($treeNode !== null) { $this->parentNode->addChildNode($this); } foreach ($this->getChildNodes() as $child) { - /** @var NodeInterface $this */ + /** @var TreeNodeInterface $this */ $child->setChildNodeOf($this); } } - public function getParentNode(): ?NodeInterface + public function getParentNode(): ?TreeNodeInterface { return $this->parentNode; } - public function setParentNode(NodeInterface $node): void + public function setParentNode(TreeNodeInterface $treeNode): void { - $this->parentNode = $node; + $this->parentNode = $treeNode; $this->setChildNodeOf($this->parentNode); } - public function getRootNode(): NodeInterface + public function getRootNode(): TreeNodeInterface { $parent = $this; while ($parent->getParentNode() !== null) { @@ -182,14 +182,14 @@ public function toJson(?Closure $prepare = null): string public function toArray(?Closure $prepare = null, ?array &$tree = null): array { if ($prepare === null) { - $prepare = function (NodeInterface $node) { + $prepare = function (TreeNodeInterface $node) { return (string) $node; }; } if ($tree === null) { $tree = [ $this->getNodeId() => [ - /** @var NodeInterface $this */ + /** @var TreeNodeInterface $this */ 'node' => $prepare($this), 'children' => [], ], @@ -215,7 +215,7 @@ public function toArray(?Closure $prepare = null, ?array &$tree = null): array public function toFlatArray(?Closure $prepare = null, ?array &$tree = null): array { if ($prepare === null) { - $prepare = function (NodeInterface $node) { + $prepare = function (TreeNodeInterface $node) { $pre = $node->getNodeLevel() > 1 ? implode('', array_fill(0, $node->getNodeLevel(), '--')) : ''; return $pre . $node; @@ -235,11 +235,11 @@ public function toFlatArray(?Closure $prepare = null, ?array &$tree = null): arr } /** - * @param NodeInterface $node + * @param TreeNodeInterface $node */ public function offsetSet($offset, $node): void { - /** @var NodeInterface $this */ + /** @var TreeNodeInterface $this */ $node->setChildNodeOf($this); } diff --git a/src/Model/Tree/NodePropertiesTrait.php b/src/Model/Tree/TreeNodePropertiesTrait.php similarity index 62% rename from src/Model/Tree/NodePropertiesTrait.php rename to src/Model/Tree/TreeNodePropertiesTrait.php index 942125d3..5a1096e0 100644 --- a/src/Model/Tree/NodePropertiesTrait.php +++ b/src/Model/Tree/TreeNodePropertiesTrait.php @@ -5,9 +5,9 @@ namespace Knp\DoctrineBehaviors\Model\Tree; use Doctrine\Common\Collections\Collection; -use Knp\DoctrineBehaviors\Contract\Model\Tree\NodeInterface; +use Knp\DoctrineBehaviors\Contract\Entity\TreeNodeInterface; -trait NodePropertiesTrait +trait TreeNodePropertiesTrait { /** * @var string @@ -15,12 +15,12 @@ trait NodePropertiesTrait protected $materializedPath = ''; /** - * @var Collection|NodeInterface[] + * @var Collection|TreeNodeInterface[] */ private $childNodes; /** - * @var NodeInterface|null + * @var TreeNodeInterface|null */ private $parentNode; } diff --git a/src/Model/Tree/TreeNodeTrait.php b/src/Model/Tree/TreeNodeTrait.php new file mode 100644 index 00000000..a3b6e935 --- /dev/null +++ b/src/Model/Tree/TreeNodeTrait.php @@ -0,0 +1,11 @@ +buildTree($results); } - public function getTreeExceptNodeAndItsChildrenQB(NodeInterface $node, string $rootAlias = 't') + public function getTreeExceptNodeAndItsChildrenQB(TreeNodeInterface $treeNode, string $rootAlias = 't') { return $this->getFlatTreeQB('', $rootAlias) ->andWhere($rootAlias . '.materializedPath NOT LIKE :except_path') ->andWhere($rootAlias . '.id != :id') - ->setParameter('except_path', $node->getRealMaterializedPath() . '%') - ->setParameter('id', $node->getId()); + ->setParameter('except_path', $treeNode->getRealMaterializedPath() . '%') + ->setParameter('id', $treeNode->getId()); } /** * Extracts the root node and constructs a tree using flat resultset - * @return ArrayAccess|NodeInterface[]|null + * @return ArrayAccess|TreeNodeInterface[]|null */ public function buildTree(array $results) { diff --git a/tests/Fixtures/Entity/TreeNodeEntity.php b/tests/Fixtures/Entity/TreeNodeEntity.php index d7032344..276d04d0 100644 --- a/tests/Fixtures/Entity/TreeNodeEntity.php +++ b/tests/Fixtures/Entity/TreeNodeEntity.php @@ -5,28 +5,22 @@ namespace Knp\DoctrineBehaviors\Tests\Fixtures\Entity; use ArrayAccess; -use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; -use Knp\DoctrineBehaviors\Contract\Model\Tree\NodeInterface; -use Knp\DoctrineBehaviors\Model\Tree\NodeTrait; +use Knp\DoctrineBehaviors\Contract\Entity\TreeNodeInterface; +use Knp\DoctrineBehaviors\Model\Tree\TreeNodeTrait; /** * @ORM\Entity(repositoryClass="Knp\DoctrineBehaviors\Tests\Fixtures\Repository\TreeNodeRepository") */ -class TreeNodeEntity implements NodeInterface, ArrayAccess +class TreeNodeEntity implements TreeNodeInterface, ArrayAccess { - use NodeTrait; - - /** - * @var string - */ - public const PATH_SEPARATOR = '/'; + use TreeNodeTrait; /** * @ORM\Column(type="string", length=255, nullable=true) * @var string */ - protected $name; + private $name; /** * @ORM\Id @@ -34,13 +28,7 @@ class TreeNodeEntity implements NodeInterface, ArrayAccess * @ORM\GeneratedValue(strategy="NONE") * @var int|null */ - protected $id; - - public function __construct(?int $id = null) - { - $this->id = $id; - $this->childNodes = new ArrayCollection(); - } + private $id; public function __toString(): string { diff --git a/tests/ORM/Tree/NodeTest.php b/tests/ORM/TreeNodeTest.php similarity index 94% rename from tests/ORM/Tree/NodeTest.php rename to tests/ORM/TreeNodeTest.php index 30ed4d0d..8ffdfbb7 100644 --- a/tests/ORM/Tree/NodeTest.php +++ b/tests/ORM/TreeNodeTest.php @@ -2,17 +2,17 @@ declare(strict_types=1); -namespace Knp\DoctrineBehaviors\Tests\ORM\Tree; +namespace Knp\DoctrineBehaviors\Tests\ORM; use Iterator; -use Knp\DoctrineBehaviors\Contract\Model\Tree\NodeInterface; +use Knp\DoctrineBehaviors\Contract\Entity\TreeNodeInterface; use Knp\DoctrineBehaviors\Tests\AbstractBehaviorTestCase; use Knp\DoctrineBehaviors\Tests\Fixtures\Entity\TreeNodeEntity; use Knp\DoctrineBehaviors\Tests\Fixtures\Repository\TreeNodeRepository; use LogicException; use Nette\Utils\Json; -final class NodeTest extends AbstractBehaviorTestCase +final class TreeNodeTest extends AbstractBehaviorTestCase { public function testBuildTree(): void { @@ -21,6 +21,7 @@ public function testBuildTree(): void 'setName' => 'root', 'setId' => 1, ]); + $flatTree = [ $this->buildNode([ 'setMaterializedPath' => '/1', @@ -100,7 +101,7 @@ public function provideRootPaths(): Iterator /** * @dataProvider provideIsChildNodeOf() */ - public function testTestisChildNodeOf(NodeInterface $child, NodeInterface $parent, $expected): void + public function testTestisChildNodeOf(TreeNodeInterface $child, TreeNodeInterface $parent, $expected): void { $this->assertSame($expected, $child->isChildNodeOf($parent)); } @@ -273,9 +274,16 @@ public function testGetTree(): void /** @var TreeNodeRepository $repository */ $repository = $this->entityManager->getRepository(TreeNodeEntity::class); - $entity = new TreeNodeEntity(1); - $entity[0] = new TreeNodeEntity(2); - $entity[0][0] = new TreeNodeEntity(3); + $entity = new TreeNodeEntity(); + $entity->setId(1); + + $secondEntity = new TreeNodeEntity(); + $secondEntity->setId(2); + $entity[0] = $secondEntity; + + $thirdEntity = new TreeNodeEntity(); + $thirdEntity->setId(3); + $entity[0][0] = $thirdEntity; $this->entityManager->persist($entity); $this->entityManager->persist($entity[0]); diff --git a/upgrade/rector/doctrine-behaviors-20.yaml b/upgrade/rector/doctrine-behaviors-20.yaml index b5ce5b14..4056f8f7 100644 --- a/upgrade/rector/doctrine-behaviors-20.yaml +++ b/upgrade/rector/doctrine-behaviors-20.yaml @@ -25,7 +25,7 @@ services: Rector\Renaming\Rector\Class_\RenameClassRector: $oldToNewClasses: # move interface to "Contract" - Knp\DoctrineBehaviors\Model\Tree\NodeInterface: 'Knp\DoctrineBehaviors\Contract\Model\Tree\NodeInterface' + Knp\DoctrineBehaviors\Model\Tree\NodeInterface: 'Knp\DoctrineBehaviors\Contract\Entity\TreeNodeInterface' # suffix "Trait" for traits Knp\DoctrineBehaviors\Model\Blameable\BlameableMethods: Knp\DoctrineBehaviors\Model\Blameable\BlameableMethodsTrait @@ -58,6 +58,9 @@ services: Knp\DoctrineBehaviors\Model\Translatable\TranslationProperties: Knp\DoctrineBehaviors\Model\Translatable\TranslationPropertiesTrait Knp\DoctrineBehaviors\Model\Translatable\Translation: Knp\DoctrineBehaviors\Model\Translatable\TranslationTrait + # tree + Knp\DoctrineBehaviors\Model\Tree\Node: 'Knp\DoctrineBehaviors\Model\Tree\TreeNodeTrait' + # @todo de-fluent method calls # add scalar types to trait methods Rector\Doctrine\Rector\Class_\AddEntityIdByConditionRector: