chamber-orchestra/doctrine-sort-bundle
Symfony bundle for automatic sort order management in Doctrine ORM entities. Recalculates sort positions on every EntityManager::flush(), keeping ordered lists consistent without manual reindexing. Uses PHP attributes to mark the sort field, supports grouped ordering (e.g., per parent or category), and handles insertions, deletions, and reordering transparently.
groupBy#[Sort] attribute on your entity property, zero YAML/XML configDEFERRED_IMPLICIT and DEFERRED_EXPLICIT trackingSortTrait and SortByParentTrait with convenience methods (moveUp, moveDown, moveToBeginning, moveToEnd)composer require chamber-orchestra/doctrine-sort-bundle
If Symfony Flex is enabled, the bundle is registered automatically. Otherwise, add it to config/bundles.php:
return [
// ...
ChamberOrchestra\DoctrineSortBundle\ChamberOrchestraDoctrineSortBundle::class => ['all' => true],
];
Add the #[Sort] attribute to any integer column. The bundle will automatically maintain sequential ordering starting from 1.
use ChamberOrchestra\DoctrineSortBundle\Mapping\Attribute\Sort;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class TodoItem
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(type: 'integer', options: ['unsigned' => true, 'default' => 0])]
#[Sort]
private int $sortOrder = 0;
// Setting sortOrder to 0 appends the item to the end of the list.
// Setting sortOrder to 1 moves it to the beginning.
// Any value in between inserts at that position; surrounding items shift automatically.
}
Maintain separate sort sequences per parent, category, or any relation:
use ChamberOrchestra\DoctrineSortBundle\Mapping\Attribute\Sort;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class Task
{
#[ORM\ManyToOne]
private ?Project $project = null;
#[ORM\Column(type: 'integer', options: ['unsigned' => true, 'default' => 0])]
#[Sort(groupBy: ['project'])]
private int $sortOrder = 0;
// Each project has its own independent sort sequence.
// Moving a task to a different project removes it from the old sequence
// and inserts it into the new one.
}
For common cases, use the provided traits instead of writing boilerplate:
use ChamberOrchestra\DoctrineSortBundle\Contracts\Entity\SortInterface;
use ChamberOrchestra\DoctrineSortBundle\Entity\SortTrait;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class TodoItem implements SortInterface
{
use SortTrait;
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
}
SortTrait provides getSortOrder(), setSortOrder(), and convenience methods:
| Method | Effect |
|---|---|
moveUp() |
Decrease sort position by 1 (minimum 1) |
moveDown() |
Increase sort position by 1 |
moveToBeginning() |
Set sort position to 1 |
moveToEnd() |
Set sort position to 0 (appends to end) |
SortByParentTrait extends SortTrait with a $parent ManyToOne field and #[Sort(groupBy: ['parent'])].
#[Sort(
groupBy: ['parent'], // Fields that define independent sort groups
evictCollections: [ // Second-level cache collections to evict on change
[ParentEntity::class, 'children'],
],
evictRegions: ['my_query_region'], // Query cache regions to evict on change
)]
| Option | Type | Default | Description |
|---|---|---|---|
groupBy |
array |
[] |
Entity field names that define sort groups. Each unique combination of group values has its own sort sequence. Supports Column, ManyToOne, and ManyToMany fields. |
evictCollections |
array |
[] |
List of [FQCN, collectionField] pairs. These Doctrine second-level cache collections are evicted when sort order changes. |
evictRegions |
array |
[] |
Query cache region names to evict when sort order changes. |
onFlush event#[Sort] attribute that was inserted, updated, or deleted, it collects the changesrecomputeSingleEntityChangeSet() ensures the corrected values are persisted in the same flushThis means you never need to manually manage gaps, shift items, or renumber sequences — just set the desired position and flush. Multiple reorder operations within a single flush or across multiple flushes in an explicit transaction are fully supported.
| Bundle | PHP | Symfony | Doctrine ORM |
|---|---|---|---|
| 8.0 | ^8.5 | 8.0 | 3.6+ |
composer test
MIT
How can I help you explore Laravel packages today?