DoctrineExtensions icon indicating copy to clipboard operation
DoctrineExtensions copied to clipboard

Duplicate position after repositioning

Open alexsegura opened this issue 2 months ago • 4 comments

Environment

Package

show

$ composer show --latest gedmo/doctrine-extensions
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
latest   : v3.21.0
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     : /Users/admin/Workspace/coopcycle-web/vendor/gedmo/doctrine-extensions
names    : gedmo/doctrine-extensions

Doctrine packages

show

$ composer show --latest 'doctrine/*'
Direct dependencies required in composer.json:
doctrine/annotations     2.0.2  2.0.2  Docblock Annotations Parser
Package doctrine/annotations is abandoned, you should avoid using it. No replacement was suggested.
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.3.0  PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.
doctrine/common          3.5.0  3.5.0  PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and muc...
doctrine/dbal            4.3.4  4.3.4  Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.
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/doctrine-bundle 2.17.1 2.17.1 Symfony DoctrineBundle
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/mongodb-odm     2.12.2 1.0.8  PHP Doctrine MongoDB Object Document Mapper (ODM) provides transparent persistence for PHP objects to MongoDB.
doctrine/orm             3.5.2  3.5.2  Object-Relational-Mapper for PHP
doctrine/persistence     4.1.0  4.1.0  The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.

Transitive dependencies not required in composer.json:
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/sql-formatter   1.5.2  1.5.2  a PHP SQL highlighting library

PHP version

$ php -v
PHP 8.3.22 (cli) (built: Jun  3 2025 17:17:57) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.22, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.22, Copyright (c), by Zend Technologies

Subject

When repositioning a node + adding a new node, positions are duplicated, resulting in a unpredictable order.

Minimal repository with the bug

I added a unit test in this repository, in the branch wrong-position, that confirms the problem

Steps to reproduce


$node1 = new Node();
$node1->setName('Node1');
$node1->setPath('/');
$node1->setPosition(0);
$this->em->persist($node1);

$node2 = new Node();
$node2->setName('Node2');
$node2->setPath('/');
$node2->setPosition(1);
$this->em->persist($node2);

$node3 = new Node();
$node3->setName('Node3');
$node3->setPath('/');
$node3->setPosition(2);
$this->em->persist($node3);

$this->em->flush();

// We change position of Node3 (it will be the last)
$node3->setPosition(3);

// We insert a node at position 2 (it will be before Node3)
$node4 = new Node();
$node4->setName('Node4');
$node4->setPath('/');
$node4->setPosition(2);

$this->em->persist($node3);
$this->em->persist($node4);
$this->em->flush();

Expected results

Elements shouldn't have the same position.

Actual results

Both Node3 & Node4 have the position 2

alexsegura avatar Oct 10 '25 09:10 alexsegura

Just for more context, it happens when doing this in the UI, which seems to me pretty common use case.

Image

alexsegura avatar Oct 10 '25 09:10 alexsegura

I think the problem has something to do with $this->maxPositions in SortableListener.

alexsegura avatar Oct 10 '25 09:10 alexsegura

I have the same problem. Duplicate sort_order

s1t2e3 avatar Nov 07 '25 15:11 s1t2e3

:)

bartko-s avatar Nov 07 '25 20:11 bartko-s