Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Sortable Behavior Bundle Laravel Package

mysam/sortable-behavior-bundle

A Symfony bundle that adds sortable behavior to Doctrine entities, making it easy to order records with position fields and reorder them in admin lists and other collections.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. composer require mysam/sortable-behavior-bundle and register Pix\SortableBehaviorBundle\PixSortableBehaviorBundle in config/bundles.php (or AppKernel).
  2. Add a position integer column to the entity you want to sort (default 0). Optionally use the bundled SortableTrait and implement SortableInterface so getPosition()/setPosition() come for free.
  3. Make the relevant Sonata Admin controller extend Pix\SortableBehaviorBundle\Controller\SortableAdminController (this bundle is a Sonata Admin listing enhancer — it assumes Sonata and Doctrine).
  4. Expose a move route (/admin/foo/move/{id}/{position}) pointing at moveAction, or reuse the bundled template which wires drag-and-drop and up/down/top/bottom buttons.
  5. First use case: a FAQ, Category, or Block listing where an editor reorders rows manually rather than editing a raw position number. Start with one admin and one entity, verify the move route flips positions, then replicate.

Where to look first:

  • Controller/SortableAdminController.php — all move/reorder logic lives here.
  • Model/SortableTrait.php + Model/SortableInterface.php — what your entity must implement.
  • Resources/views/ — the list template that renders drag handles and buttons.
  • DependencyInjection/Configuration.php — sortable_groups and other config keys.
  • Tests/ (if present) — most reliable guide to the actual method signatures.

Implementation Patterns

Basic admin. Add a fake action column that renders the move widget:

protected function configureListFields(ListMapper $listMapper)
{
    $listMapper
        ->addIdentifier('id')
        ->add('name')
        ->add('_action', null, [
            'actions' => [
                'move' => [
                    'template' => '@PixSortableBehavior/Default/_sort_drag_drop.html.twig',
                    'enable_top_bottom_buttons' => true,
                ],
            ],
        ]);
}

Group-scoped sorting. When rows belong to a parent (category, page, tenant), configure the group field so position is scoped per group rather than global. Override the group getter in your admin if the config key isn't enough — most real deployments end up doing that.

Subclass, don't fork. Override getPositionFieldName() if you're not using position, and override the move handler if you need custom redirects or flash messages. The controller methods are small and meant to be extended.

Drag-and-drop. The bundled template expects jQuery UI sortable plus the Sonata list layout. Ensure the assets are loaded via sonata_admin.assets and that your list template is the one the bundle ships; swapping in a custom list.html.twig usually means also copying the drag JS.

Programmatic reordering. setPosition($n); flush(); alone is not enough — you'll collide with siblings. Either funnel changes through the bundle's position handler, or in a transaction: shift affected rows, set the target, then reindex the whole group. Fixtures and tests need this just as much as user actions.

Integration tip. Treat the bundle as the UI layer only. Keep position maintained on prePersist/preUpdate (see gotchas) so imports, API writes, and fixtures don't leave the column in a broken state.

Gotchas and Tips

  • Version ceiling. Last release 2020 → targets Sonata Admin 3.x, Symfony 4.4/5.x, PHP 7.x. On Sonata 4/5 or Symfony 6 you'll hit template-block and method-signature breaks. Pin versions or budget a fork.
  • Zero adoption / zero stars. No community safety net. Read the controller and trait before trusting a remembered upstream API; the fork may diverge from the original Pix bundle.
  • New rows land at position = 0. Nothing sets the next index automatically in every path. Add a prePersist listener that sets position = MAX(position) + 1 within the group, or every new entity piles on the same slot.
  • Group moves create holes and dupes. Moving an entity to another parent leaves a gap in the old group and a collision in the new one. Reindex both groups after any group change.
  • No concurrency control. Two editors dragging simultaneously can produce duplicate positions. Wrap moves in a transaction and reindex the group if ordering matters to business logic.
  • Stale lists after a move. moveAction should redirect to the list/referer. If the UI looks unchanged, check the response redirect and the Sonata pager's sort/order — the list can be re-sorted client-side and mask your change.
  • Don't sort by position in configureListFields alone. Pair it with the pager's default sort, or Sonata's datagrid may show rows out of order regardless of the column values.
  • Debugging almost always means inspecting the column. SELECT id, position FROM foo ORDER BY position — holes and duplicates account for most "it moved the wrong row" reports.
  • Extension points beat configuration. Subclass the controller, override the position field name and group getter, swap the template. The bundle is small enough that a local patch is often cheaper than fighting config options that don't exist.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core