Weave Code
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

pixassociates/sortable-behavior-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require pixassociates/sortable-behavior-bundle
    

    Enable the bundle in app/AppKernel.php:

    new Pix\SortableBehaviorBundle\PixSortableBehaviorBundle(),
    
  2. Basic Configuration: Add to app/config/config.yml:

    pix_sortable_behavior:
        db_driver: orm  # or 'mongodb'
        position_field:
            default: sort
            entities:
                AppBundle\Entity\YourEntity: position
    
  3. Entity Setup: Add a position field to your entity (e.g., YourEntity):

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $position;
    
  4. Admin Integration: Extend SonataAdminBundle and configure the list fields:

    protected function configureListFields(ListMapper $listMapper) {
        $listMapper
            ->add('_action', 'actions', [
                'actions' => [
                    'move' => ['template' => 'PixSortableBehaviorBundle:Default:_sort.html.twig']
                ]
            ]);
    }
    
  5. First Use Case: Clear cache and visit your admin listing. The default up/down arrows will appear next to each row, allowing manual sorting.


Implementation Patterns

Workflows

  1. Manual Sorting (Default):

    • Use the default _sort.html.twig template for up/down buttons.
    • Works out-of-the-box with the configuration above.
  2. Drag-and-Drop Sorting:

    • Override the move action template in your admin class:
      protected function configureListFields(ListMapper $listMapper) {
          $listMapper
              ->add('_action', null, [
                  'actions' => [
                      'move' => [
                          'template' => 'PixSortableBehaviorBundle:Default:_sort_drag_drop.html.twig'
                      ]
                  ]
              ]);
      }
      
    • Ensure jQuery UI is loaded in your admin template (check Sonata’s base.html.twig for includes).
  3. Grouped Sorting:

    • Configure sortable_groups in config.yml to enable sorting by groups:
      pix_sortable_behavior:
          sortable_groups:
              entities:
                  AppBundle\Entity\Baz: [group_field_name]
      
    • Override the template to include group-specific logic (e.g., AppBundle:Admin:_sort_grouped.html.twig).
  4. Custom Position Field:

    • Override the default position field per entity:
      pix_sortable_behavior:
          position_field:
              entities:
                  AppBundle\Entity\CustomEntity: custom_sort_order
      

Integration Tips

  • Doctrine Events: Listen for preUpdate/prePersist to auto-generate position values if needed:

    $entity->setPosition($entity->getPosition() ?: $this->getMaxPosition() + 1);
    
  • Batch Updates: Use Doctrine’s createQueryBuilder() to update positions in bulk when reordering multiple items:

    $qb = $em->createQueryBuilder()
        ->update('AppBundle:YourEntity', 'e')
        ->set('e.position', ':position')
        ->where('e.id IN (:ids)')
        ->setParameter('ids', $ids)
        ->setParameter('position', $position);
    
  • AJAX Handling: Extend the move action in your admin controller to handle AJAX requests:

    public function moveAction(Request $request) {
        $response = parent::moveAction($request);
        return $this->render('AppBundle:Admin:_sort_ajax.html.twig', [
            'admin' => $this,
            'response' => $response
        ]);
    }
    
  • Template Overrides: Copy templates from vendor/pixassociates/sortable-behavior-bundle/Resources/views/Default/ to app/Resources/PixSortableBehaviorBundle/views/Default/ for customization.


Gotchas and Tips

Pitfalls

  1. Cache Issues:

    • Always clear the cache after configuration changes:
      php bin/console cache:clear
      
    • If sorting doesn’t appear, check if the _action field is rendered in the list template.
  2. Position Field Conflicts:

    • Ensure the position field is nullable (nullable=true) if you’re using auto-increment logic.
    • Avoid naming conflicts with existing fields (e.g., sort, order, position).
  3. Drag-and-Drop Dependencies:

    • The drag-and-drop feature requires jQuery UI. If missing, the feature will fail silently. Add to base.html.twig:
      {{ sonata_block_render_event('sonata.admin.extend.javascript', { 'group': 'sonata_admin' }) }}
      
      Or manually include:
      {{ sonata_jqueryui_bundle_jqueryui() }}
      
  4. MongoDB Quirks:

    • If using MongoDB, ensure the position field is indexed for performance:
      /**
       * @MongoDB\Index(keys={"position"="asc"})
       */
      */
      
  5. Sonata Admin Version Mismatch:

    • The bundle is tested with SonataAdminBundle 3.x. If using v4+, check for compatibility issues (e.g., ListMapper changes).
  6. CSRF Token Errors:

    • The move action may fail with CSRF errors if the route is not properly configured. Extend the route in your admin class:
      protected function configureRoutes(RouteCollection $collection) {
          $collection->add('move', $this->getRouterIdParameter() . '/move');
      }
      

Debugging

  1. Check Database:

    • Verify the position field is being updated:
      SELECT id, position FROM your_entity ORDER BY position;
      
  2. Log AJAX Requests:

    • Enable Symfony’s profiler to inspect AJAX requests:
      // config_dev.yml
      framework:
          profiler: { only_exceptions: false }
      
  3. Template Debugging:

    • Override _sort.html.twig and add debug output:
      <pre>{{ dump(admin) }}</pre>
      

Extension Points

  1. Custom Sort Logic:

    • Override the move action in your admin controller to implement custom sorting logic:
      public function moveAction(Request $request) {
          $id = $request->request->get('id');
          $direction = $request->request->get('direction');
          $entity = $this->getModelManager()->find($this->getClass(), $id);
      
          if ($direction === 'up') {
              $this->swapPositions($entity, 'down');
          } else {
              $this->swapPositions($entity, 'up');
          }
      
          return $this->render('PixSortableBehaviorBundle:Default:_sort.html.twig', [
              'admin' => $this,
              'object' => $entity
          ]);
      }
      
      private function swapPositions($entity, $direction) {
          $em = $this->getModelManager()->getEntityManager();
          $repo = $em->getRepository($this->getClass());
      
          if ($direction === 'up') {
              $currentPos = $entity->getPosition();
              $entity->setPosition($currentPos - 1);
              $sibling = $repo->findOneBy(['position' => $currentPos - 1]);
              $sibling->setPosition($currentPos);
          } else {
              // 'down' logic
          }
      
          $em->flush();
      }
      
  2. Event Listeners:

    • Listen for sonata.admin.action.move events to add pre/post-processing:
      // services.yml
      services:
          app.sortable_listener:
              class: AppBundle\EventListener\SortableListener
              tags:
                  - { name: kernel.event_listener, event: sonata.admin.action.move, method: onMove }
      
  3. Custom Templates:

    • Extend the default templates to add features like:
      • Batch reordering: Modify _sort_drag_drop.html.twig to support multi-item drag.
      • Visual feedback: Add CSS classes for drag states (e.g., .dragging).
  4. API Integration:

    • Expose sorting via API by extending the move action to return JSON:
      public function moveAction(Request $request) {
          // ... existing logic ...
          return new JsonResponse(['success' => true, 'position' => $entity->getPosition()]);
      }
      
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.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware