-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Open
Description
Environment
php 8.4.13Linux 88ac4bca2e3b 6.12.54-linuxkit #1 SMP Tue Nov 4 21:21:47 UTC 2025 aarch64Symfony 7.3.4
Package
show
name : gedmo/doctrine-extensions
descrip. : Doctrine behavioral extensions
keywords : Blameable, behaviors, doctrine, extensions, gedmo, loggable, nestedset, odm, orm, sluggable, sortable, timestampable, translatable, tree, uploadable
versions : * v3.21.0
released : 2025-09-22, 1 month ago
latest : v3.21.0 released 2025-09-22, 1 month ago
type : library
license : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText
homepage : http://gediminasm.org/
source : [git] https://github.com/doctrine-extensions/DoctrineExtensions.git eb53dfcb2b592327b76ac5226fbb003d32aea37e
dist : [zip] https://api.github.com/repos/doctrine-extensions/DoctrineExtensions/zipball/eb53dfcb2b592327b76ac5226fbb003d32aea37e eb53dfcb2b592327b76ac5226fbb003d32aea37e
path : /user/domains/Dev/site/vendor/gedmo/doctrine-extensions
names : gedmo/doctrine-extensions
support
docs : https://github.com/doctrine-extensions/DoctrineExtensions/tree/main/doc
issues : https://github.com/doctrine-extensions/DoctrineExtensions/issues
source : https://github.com/doctrine-extensions/DoctrineExtensions/tree/v3.21.0
autoload
psr-4
Gedmo\ => src/
requires
doctrine/collections ^1.2 || ^2.0
doctrine/deprecations ^1.0
doctrine/event-manager ^1.2 || ^2.0
doctrine/persistence ^2.2 || ^3.0 || ^4.0
php ^7.4 || ^8.0
psr/cache ^1 || ^2 || ^3
psr/clock ^1
symfony/cache ^5.4 || ^6.0 || ^7.0
symfony/string ^5.4 || ^6.0 || ^7.0
requires (dev)
behat/transliterator ^1.2
doctrine/annotations ^1.13 || ^2.0
doctrine/cache ^1.11 || ^2.0
doctrine/common ^2.13 || ^3.0
doctrine/dbal ^3.7 || ^4.0
doctrine/doctrine-bundle ^2.3
doctrine/mongodb-odm ^2.3
doctrine/orm ^2.20 || ^3.3
friendsofphp/php-cs-fixer ^3.70
nesbot/carbon ^2.71 || ^3.0
phpstan/phpstan ^2.1.1
phpstan/phpstan-doctrine ^2.0.1
phpstan/phpstan-phpunit ^2.0.3
phpunit/phpunit ^9.6
rector/rector ^2.0.6
symfony/console ^5.4 || ^6.0 || ^7.0
symfony/doctrine-bridge ^5.4 || ^6.0 || ^7.0
symfony/phpunit-bridge ^6.4 || ^7.0
symfony/uid ^5.4 || ^6.0 || ^7.0
symfony/yaml ^5.4 || ^6.0 || ^7.0
suggests
doctrine/mongodb-odm to use the extensions with the MongoDB ODM
doctrine/orm to use the extensions with the ORM
conflicts
behat/transliterator <1.2 || >=2.0
doctrine/annotations <1.13 || >=3.0
doctrine/common <2.13 || >=4.0
doctrine/dbal <3.7 || >=5.0
doctrine/mongodb-odm <2.3 || >=3.0
doctrine/orm <2.20 || >=3.0 <3.3 || >=4.0
Doctrine packages
show
Color legend:
- patch or minor release available - update recommended
- major release available - update possible
- up to date version
Direct dependencies required in composer.json:
doctrine/dbal 3.9.3 4.3.4 Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.
doctrine/doctrine-bundle 2.18.0 3.0.0 Symfony DoctrineBundle
doctrine/doctrine-migrations-bundle 3.5.0 3.7.0 Symfony DoctrineMigrationsBundle
doctrine/orm 3.5.2 3.5.7 Object-Relational-Mapper for PHP
Transitive dependencies not required in composer.json:
doctrine/cache 2.2.0 2.2.0 PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.
Package doctrine/cache is abandoned, you should avoid using it. No replacement was suggested.
doctrine/collections 2.3.0 2.4.0 PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.
doctrine/deprecations 1.1.5 1.1.5 A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.
doctrine/event-manager 2.0.1 2.0.1 The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.
doctrine/inflector 2.1.0 2.1.0 PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.
doctrine/instantiator 2.0.0 2.0.0 A small, lightweight utility to instantiate objects in PHP without invoking their constructors
doctrine/lexer 3.0.1 3.0.1 PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.
doctrine/migrations 3.9.4 3.9.5 PHP Doctrine Migrations project offer additional functionality on top of the database abstraction layer (DBAL) for versioning your database schema and easily de...
doctrine/persistence 4.1.1 4.1.1 The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.
doctrine/sql-formatter 1.5.2 1.5.3 a PHP SQL highlighting library
PHP version
PHP 8.4.13 (cli) (built: Sep 30 2025 00:02:18) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.4.13, Copyright (c) Zend Technologies
with Zend OPcache v8.4.13, Copyright (c), by Zend Technologies
Subject
This is the error obtained, which happens at ORM::updatePositions due to the fact that all Gallery items are deleted, the gallery is deleted and also its parent. I believe there's a miscalculation, making the following code fail:
foreach ($relocation['groups'] as $group => $value) {
if (null === $value) {
$dql .= " AND n.{$group} IS NULL";
} else {
$dql .= " AND n.{$group} = :val___".(++$i);
$params['val___'.$i] = $value;
}
}
Since $value is not present; Gallery is there, but its id = null
$em = $this->getObjectManager();
$q = $em->createQuery($dql);
$q->setParameters($params);
$q->getSingleScalarResult();
giving this error:
Binding entities to query parameters only allowed for entities that have an identifier.
Class "App\Entity\Gallery" does not have an identifier.
That's why we suspect that even doctrine marking ParentA, its Gallery children and their Items deleted, Sortable is not keeping track of this, causing it to try to sort deleted items.
Minimal repository with the bug
Not sure
Steps to reproduce
Here's a reproducible case with all needed entities, migrations and a simple test case.
Entities
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class ParentA
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
private ?Gallery $gallery = null;
public function getId(): ?int
{
return $this->id;
}
public function getGallery(): ?Gallery
{
return $this->gallery;
}
public function setGallery(?Gallery $gallery): static
{
$this->gallery = $gallery;
return $this;
}
}
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class Gallery
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
/**
* @var Collection<int, Items>
*/
#[ORM\OneToMany(targetEntity: Items::class, mappedBy: 'gallery', orphanRemoval: true)]
private Collection $items;
public function __construct()
{
$this->items = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
/**
* @return Collection<int, Items>
*/
public function getItems(): Collection
{
return $this->items;
}
public function addItem(Items $item): static
{
if (!$this->items->contains($item)) {
$this->items->add($item);
$item->setGallery($this);
}
return $this;
}
public function removeItem(Items $item): static
{
if ($this->items->removeElement($item)) {
// set the owning side to null (unless already changed)
if ($item->getGallery() === $this) {
$item->setGallery(null);
}
}
return $this;
}
}
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
#[ORM\Entity]
class Items
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(inversedBy: 'items')]
#[ORM\JoinColumn(nullable: false)]
#[Gedmo\SortableGroup]
private ?Gallery $gallery = null;
#[ORM\Column(options: ['default' => 0])]
#[Gedmo\SortablePosition]
private ?int $position = 0;
public function getId(): ?int
{
return $this->id;
}
public function getGallery(): ?Gallery
{
return $this->gallery;
}
public function setGallery(?Gallery $gallery): static
{
$this->gallery = $gallery;
return $this;
}
public function getPosition(): int
{
return $this->position;
}
public function setPosition(int $position): static
{
$this->position = $position;
return $this;
}
}
Migrations
$this->addSql('CREATE TABLE gallery (id INT AUTO_INCREMENT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_general_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE items (id INT AUTO_INCREMENT NOT NULL, gallery_id INT NOT NULL, INDEX IDX_E11EE94D4E7AF8F (gallery_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_general_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE parent_a (id INT AUTO_INCREMENT NOT NULL, gallery_id INT DEFAULT NULL, UNIQUE INDEX UNIQ_7C1C0DB64E7AF8F (gallery_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_general_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE items ADD CONSTRAINT FK_E11EE94D4E7AF8F FOREIGN KEY (gallery_id) REFERENCES gallery (id)');
$this->addSql('ALTER TABLE parent_a ADD CONSTRAINT FK_7C1C0DB64E7AF8F FOREIGN KEY (gallery_id) REFERENCES gallery (id)');
$this->addSql('ALTER TABLE items ADD position INT DEFAULT 0 NOT NULL');
$this->addSql('INSERT INTO `gallery` (`id`) VALUES (\'1\')');
$this->addSql('INSERT INTO `items` (`gallery_id`) VALUES (\'1\')');
$this->addSql('INSERT INTO `items` (`gallery_id`) VALUES (\'1\')');
$this->addSql('INSERT INTO `items` (`gallery_id`) VALUES (\'1\')');
$this->addSql('INSERT INTO `parent_a` (`gallery_id`) VALUES (\'1\');');
Controller
<?php
declare(strict_types=1);
namespace App\Controller;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\ParentA;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class TestController extends AbstractController
{
public function __construct(
private EntityManagerInterface $em
) {
}
public function __invoke(): Response
{
$entity = $this->em->getRepository(ParentA::class)->find(1);
dump($entity);
$this->em->remove($entity);
$this->em->flush();
dd($entity);
}
}
Expected results
No error is shown and the sorting is properly done.
Actual results
Binding entities to query parameters only allowed for entities that have an identifier.
Class "App\Entity\Gallery" does not have an identifier.
Metadata
Metadata
Assignees
Labels
No labels