From feedb02af2842ca6064f343acf2afaf0a8d6f8b3 Mon Sep 17 00:00:00 2001 From: Michael Babker Date: Mon, 26 Feb 2024 21:18:58 -0500 Subject: [PATCH] Add tests for #2701 --- composer.json | 3 + .../Gedmo/Tree/Fixture/Issue2701/Category.php | 152 ++++++++++++++++++ tests/Gedmo/Tree/Issue/Issue2701Test.php | 124 ++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 tests/Gedmo/Tree/Fixture/Issue2701/Category.php create mode 100644 tests/Gedmo/Tree/Issue/Issue2701Test.php diff --git a/composer.json b/composer.json index 4799df4206..35f61ca759 100644 --- a/composer.json +++ b/composer.json @@ -64,9 +64,12 @@ "phpstan/phpstan-doctrine": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^9.6", + "psr/container": "^1.0 | ^2.0", "rector/rector": "^0.19", "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/doctrine-bridge": "^5.4 || ^6.0 || ^7.0", "symfony/phpunit-bridge": "^6.0 || ^7.0", + "symfony/uid": "^5.4 || ^6.0 || ^7.0", "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, "conflict": { diff --git a/tests/Gedmo/Tree/Fixture/Issue2701/Category.php b/tests/Gedmo/Tree/Fixture/Issue2701/Category.php new file mode 100644 index 0000000000..8569c7e499 --- /dev/null +++ b/tests/Gedmo/Tree/Fixture/Issue2701/Category.php @@ -0,0 +1,152 @@ + 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\Issue2701; + +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping as ORM; +use Gedmo\Mapping\Annotation as Gedmo; +use Gedmo\Tree\Entity\Repository\NestedTreeRepository; +use Symfony\Bridge\Doctrine\Types\UlidType; +use Symfony\Component\Uid\Ulid; + +/** + * @Gedmo\Tree(type="nested") + * + * @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository") + * @ORM\Table(indexes={@ORM\Index(columns={"lft", "rgt"}, name="idx_tree")}) + */ +#[Gedmo\Tree(type: 'nested')] +#[ORM\Entity(repositoryClass: NestedTreeRepository::class)] +#[ORM\Index(columns: ['lft', 'rgt'], name: 'idx_tree')] +class Category +{ + /** + * @ORM\Column(type="ulid", unique=true) + * @ORM\Id + * @ORM\GeneratedValue(strategy="CUSTOM") + * @ORM\CustomIdGenerator(class="doctrine.ulid_generator") + */ + #[ORM\Id] + #[ORM\Column(type: UlidType::NAME, unique: true)] + #[ORM\GeneratedValue(strategy: 'CUSTOM')] + #[ORM\CustomIdGenerator(class: 'doctrine.ulid_generator')] + private ?Ulid $id = null; + + /** + * @ORM\Column(length=255) + */ + #[ORM\Column(length: 255)] + private ?string $name = null; + + /** + * @Gedmo\TreeLeft + * + * @ORM\Column(name="lft", type="integer") + */ + #[Gedmo\TreeLeft] + #[ORM\Column(name: 'lft', type: Types::INTEGER)] + public ?int $lft; + + /** + * @Gedmo\TreeLevel + * + * @ORM\Column(name="lvl", type="integer") + */ + #[Gedmo\TreeLevel] + #[ORM\Column(name: 'lvl', type: Types::INTEGER)] + private ?int $lvl; + + /** + * @Gedmo\TreeRight + * + * @ORM\Column(name="rgt", type="integer") + */ + #[Gedmo\TreeRight] + #[ORM\Column(name: 'rgt', type: Types::INTEGER)] + public ?int $rgt; + + /** + * @Gedmo\TreeRoot + * + * @ORM\ManyToOne(targetEntity="Gedmo\Tests\Tree\Fixture\Issue2701\Category") + * @ORM\JoinColumn(name="tree_root", referencedColumnName="id", onDelete="CASCADE") + */ + #[Gedmo\TreeRoot] + #[ORM\ManyToOne(targetEntity: self::class)] + #[ORM\JoinColumn(name: 'tree_root', referencedColumnName: 'id', onDelete: 'CASCADE')] + private ?self $root; + + /** + * @Gedmo\TreeParent + * + * @ORM\ManyToOne(targetEntity="Gedmo\Tests\Tree\Fixture\Issue2701\Category", inversedBy="children") + * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE") + */ + #[Gedmo\TreeParent] + #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] + #[ORM\JoinColumn(name: 'parent_id', referencedColumnName: 'id', onDelete: 'CASCADE')] + private ?self $parent; + + /** + * @var Collection|self[] + * + * @ORM\OneToMany(targetEntity="Gedmo\Tests\Tree\Fixture\Issue2701\Category", mappedBy="parent") + * @ORM\OrderBy({"lft" = "ASC"}) + */ + #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')] + #[ORM\OrderBy(['lft' => 'ASC'])] + private Collection $children; + + public function __construct() + { + $this->children = new ArrayCollection(); + } + + public function getId(): ?Ulid + { + return $this->id; + } + + public function getName(): ?string + { + return $this->name; + } + + public function setName(string $name): static + { + $this->name = $name; + + return $this; + } + + public function setTranslatableLocale(string $locale): void + { + $this->locale = $locale; + } + + public function getRoot(): ?self + { + return $this->root; + } + + public function setParent(?self $parent = null): void + { + $this->parent = $parent; + } + + public function getParent(): ?self + { + return $this->parent; + } +} diff --git a/tests/Gedmo/Tree/Issue/Issue2701Test.php b/tests/Gedmo/Tree/Issue/Issue2701Test.php new file mode 100644 index 0000000000..b1fac8a751 --- /dev/null +++ b/tests/Gedmo/Tree/Issue/Issue2701Test.php @@ -0,0 +1,124 @@ + 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\Bundle\DoctrineBundle\Mapping\ClassMetadataFactory; +use Doctrine\Bundle\DoctrineBundle\Mapping\MappingDriver; +use Doctrine\Common\EventManager; +use Doctrine\DBAL\Types\Type; +use Doctrine\Persistence\Mapping\Driver\MappingDriver as MappingDriverInterface; +use Gedmo\Tests\Tool\BaseTestCaseORM; +use Gedmo\Tests\Tree\Fixture\Issue2701\Category; +use Gedmo\Tree\TreeListener; +use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; +use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator; +use Symfony\Bridge\Doctrine\Types\UlidType; +use Symfony\Component\Uid\Factory\UlidFactory; + +final class Issue2701Test extends BaseTestCaseORM +{ + private TreeListener $listener; + + protected function setUp(): void + { + parent::setUp(); + + $this->listener = new TreeListener(); + + $evm = new EventManager(); + $evm->addEventSubscriber($this->listener); + + $config = $this->getDefaultConfiguration(); + $config->setClassMetadataFactoryName(ClassMetadataFactory::class); + + $mappingDriver = $config->getMetadataDriverImpl(); + + assert($mappingDriver instanceof MappingDriverInterface); + + $config->setMetadataDriverImpl(new MappingDriver($mappingDriver, $this->createIdGeneratorLocator())); + + Type::addType(UlidType::NAME, UlidType::class); + + $this->getDefaultMockSqliteEntityManager($evm, $config); + } + + protected function tearDown(): void + { + parent::tearDown(); + + // To avoid state bleedout between test cases, we will clear the type registry using brute force + $refl = (new \ReflectionClass(Type::class))->getProperty('typeRegistry'); + $refl->setAccessible(true); + $refl->setValue(Type::class, null); + } + + public function testGetNextSiblingsWithoutIdentifierMethod(): void + { + $food = new Category(); + $food->setName('Food'); + + $fruits = new Category(); + $fruits->setName('Fruits'); + $fruits->setParent($food); + + $vegetables = new Category(); + $vegetables->setName('Vegetables'); + $vegetables->setParent($food); + + $carrots = new Category(); + $carrots->setName('Carrots'); + $carrots->setParent($vegetables); + + $this->em->persist($food); + $this->em->persist($fruits); + $this->em->persist($vegetables); + $this->em->persist($carrots); + $this->em->flush(); + + $categoryRepository = $this->em->getRepository(Category::class); + + static::assertTrue($categoryRepository->verify()); + } + + protected function createIdGeneratorLocator(): ContainerInterface + { + return new class(new UlidGenerator(new UlidFactory())) implements ContainerInterface { + private UlidGenerator $ulidGenerator; + + public function __construct(UlidGenerator $ulidGenerator) + { + $this->ulidGenerator = $ulidGenerator; + } + + public function get(string $id) + { + if ('doctrine.ulid_generator' === $id) { + return $this->ulidGenerator; + } + + throw new class(sprintf('Service ID "%s" not found.', $id)) extends \InvalidArgumentException implements NotFoundExceptionInterface { + }; + } + + public function has(string $id): bool + { + return 'doctrine.ulid_generator' === $id; + } + }; + } + + protected function getUsedEntityFixtures(): array + { + return [Category::class]; + } +}