Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Tree/Strategy/ORM/Nested.php
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,11 @@ public function updateNode(EntityManagerInterface $em, $node, $parent, $position
$wrapped->setPropertyValue($config['right'], $right);
}
$newRoot = $parentRoot;

if (!isset($this->treeEdges[$meta->getName()])) {
$this->treeEdges[$meta->getName()] = $this->max($em, $config['useObjectClass'], $newRoot) + 1;
}
$this->treeEdges[$meta->getName()] += 2;
} elseif (!isset($config['root'])
|| ($meta->isSingleValuedAssociation($config['root']) && null !== $parent && ($newRoot = $meta->getFieldValue($node, $config['root'])))) {
if (!isset($this->treeEdges[$meta->getName()])) {
Expand Down
132 changes: 132 additions & 0 deletions tests/Gedmo/Tree/Fixture/Issue2582/OU.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php

/*
* This file is part of the Doctrine Behavioral Extensions package.
* (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Gedmo\Tests\Tree\Fixture\Issue2582;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

/**
* @Gedmo\Tree(type="nested")
*
* @ORM\Table(
* name="ous",
* indexes={
* @ORM\Index(name="idx_tree", fields={"left", "right"})
* }
* )
* @ORM\Entity()
*/
#[ORM\Table(name: 'ous')]
#[ORM\Index(name: 'idx_tree', columns: ['lft', 'rgt'])]
#[ORM\Entity]
#[Gedmo\Tree(type: 'nested')]
class OU
{
/**
* @ORM\Column(name="id", type="guid")
* @ORM\Id()
*/
#[ORM\Column('id', 'guid')]
#[ORM\Id]
private string $id;

/**
* @Gedmo\TreeParent()
*
* @ORM\ManyToOne(targetEntity="\Gedmo\Tests\Tree\Fixture\Issue2582\OU", inversedBy="children")
* @ORM\JoinColumn(name="parent", referencedColumnName="id", nullable=true, onDelete="CASCADE")
*/
#[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')]
#[ORM\JoinColumn(name: 'parent', referencedColumnName: 'id', nullable: true, onDelete: 'CASCADE')]
#[Gedmo\TreeParent]
private ?self $parent = null;

/**
* @Gedmo\TreeLeft()
*
* @ORM\Column(name="lft", type="integer", options={"unsigned"=true})
*/
#[ORM\Column(name: 'lft', type: 'integer', options: ['unsigned' => true])]
#[Gedmo\TreeLeft]
private int $left = 1;

/**
* @Gedmo\TreeLevel()
*
* @ORM\Column(name="lvl", type="integer", options={"unsigned"=true})
*/
#[ORM\Column(name: 'lvl', type: 'integer', options: ['unsigned' => true])]
#[Gedmo\TreeLevel]
private int $level = 0;

/**
* @Gedmo\TreeRight()
*
* @ORM\Column(name="rgt", type="integer", options={"unsigned"=true})
*/
#[ORM\Column(name: 'rgt', type: 'integer', options: ['unsigned' => true])]
#[Gedmo\TreeRight]
private int $right = 2;

/**
* @ORM\OneToMany(targetEntity="\Gedmo\Tests\Tree\Fixture\Issue2582\OU", mappedBy="parent")
* @ORM\OrderBy({"left" = "ASC"})
*
* @var Collection<int, self>
*/
#[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')]
#[ORM\OrderBy(['left' => 'ASC'])]
private Collection $children;

public function __construct(string $id, ?self $parent = null)
{
$this->id = $id;
$this->children = new ArrayCollection();
$this->parent = $parent;
if ($parent) {
$parent->children->add($this);
}
}

public function getId(): string
{
return $this->id;
}

public function getParent(): ?self
{
return $this->parent;
}

public function getLeft(): int
{
return $this->left;
}

public function getLevel(): int
{
return $this->level;
}

public function getRight(): int
{
return $this->right;
}

/**
* @return Collection<int, self>
*/
public function getChildren(): Collection
{
return $this->children;
}
}
157 changes: 157 additions & 0 deletions tests/Gedmo/Tree/Issue/Issue2582Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?php

/*
* This file is part of the Doctrine Behavioral Extensions package.
* (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Gedmo\Tests\Tree\Issue;

use Doctrine\Common\EventManager;
use Gedmo\Tests\Tool\BaseTestCaseORM;
use Gedmo\Tests\Tree\Fixture\Issue2582\OU;
use Gedmo\Tree\TreeListener;

class Issue2582Test extends BaseTestCaseORM
{
private TreeListener $listener;

protected function setUp(): void
{
parent::setUp();

$this->listener = new TreeListener();

$evm = new EventManager();
$evm->addEventSubscriber($this->listener);

$this->getDefaultMockSqliteEntityManager($evm);
}

public function testInsertTwoRootsInOneFlush(): void
{
$ou1 = new OU('00000000-0000-0000-0000-000000000001', null);
$ou11 = new OU('00000000-0000-0000-0000-000000000011', $ou1);
$ou2 = new OU('00000000-0000-0000-0000-000000000002', null);
$ou21 = new OU('00000000-0000-0000-0000-000000000021', $ou2);

$this->em->persist($ou1);
$this->em->persist($ou11);
$this->em->persist($ou2);
$this->em->persist($ou21);
$this->em->flush();

$this->em->clear();

$expected = [
['00000000-0000-0000-0000-000000000001', null, 1, 0, 4],
['00000000-0000-0000-0000-000000000011', '00000000-0000-0000-0000-000000000001', 2, 1, 3],
['00000000-0000-0000-0000-000000000002', null, 5, 0, 8],
['00000000-0000-0000-0000-000000000021', '00000000-0000-0000-0000-000000000002', 6, 1, 7],
];
foreach ($this->fetchAllOUs() as $i => $a) {
static::assertSame(
$expected[$i],
[
$a->getId(),
$a->getParent() ? $a->getParent()->getId() : null,
$a->getLeft(),
$a->getLevel(),
$a->getRight(),
],
);
}
}

public function testInsertTwoRootsInOneFlushRootsFirst(): void
{
$ou1 = new OU('00000000-0000-0000-0000-000000000001', null);
$ou11 = new OU('00000000-0000-0000-0000-000000000011', $ou1);
$ou2 = new OU('00000000-0000-0000-0000-000000000002', null);
$ou21 = new OU('00000000-0000-0000-0000-000000000021', $ou2);

$this->em->persist($ou1);
$this->em->persist($ou2);
$this->em->persist($ou11);
$this->em->persist($ou21);
$this->em->flush();

$this->em->clear();

$expected = [
['00000000-0000-0000-0000-000000000001', null, 1, 0, 4],
['00000000-0000-0000-0000-000000000011', '00000000-0000-0000-0000-000000000001', 2, 1, 3],
['00000000-0000-0000-0000-000000000002', null, 5, 0, 8],
['00000000-0000-0000-0000-000000000021', '00000000-0000-0000-0000-000000000002', 6, 1, 7],
];
foreach ($this->fetchAllOUs() as $i => $a) {
static::assertSame(
$expected[$i],
[
$a->getId(),
$a->getParent() ? $a->getParent()->getId() : null,
$a->getLeft(),
$a->getLevel(),
$a->getRight(),
],
);
}
}

public function testInsertTwoRootsInTwoFlushes(): void
{
$ou1 = new OU('00000000-0000-0000-0000-000000000001', null);
$ou11 = new OU('00000000-0000-0000-0000-000000000011', $ou1);
$ou2 = new OU('00000000-0000-0000-0000-000000000002', null);
$ou21 = new OU('00000000-0000-0000-0000-000000000021', $ou2);

$this->em->persist($ou1);
$this->em->persist($ou11);
$this->em->flush();
$this->em->persist($ou2);
$this->em->persist($ou21);
$this->em->flush();

$this->em->clear();

$expected = [
['00000000-0000-0000-0000-000000000001', null, 1, 0, 4],
['00000000-0000-0000-0000-000000000011', '00000000-0000-0000-0000-000000000001', 2, 1, 3],
['00000000-0000-0000-0000-000000000002', null, 5, 0, 8],
['00000000-0000-0000-0000-000000000021', '00000000-0000-0000-0000-000000000002', 6, 1, 7],
];
foreach ($this->fetchAllOUs() as $i => $a) {
static::assertSame(
$expected[$i],
[
$a->getId(),
$a->getParent() ? $a->getParent()->getId() : null,
$a->getLeft(),
$a->getLevel(),
$a->getRight(),
],
);
}
}

protected function getUsedEntityFixtures(): array
{
return [OU::class];
}

/**
* @return list<OU>
*/
private function fetchAllOUs(): array
{
$categoryRepo = $this->em->getRepository(OU::class);

return $categoryRepo
->createQueryBuilder('ou')
->orderBy('ou.left', 'ASC')
->getQuery()
->getResult();
}
}