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 Laravel Package

rutorika/sortable

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require rutorika/sortable
    

    Ensure compatibility with your Laravel version (see version table).

  2. Publish Config (optional):

    php artisan vendor:publish --provider="Rutorika\Sortable\SortableServiceProvider"
    

    Configures default behavior (e.g., sortable_column, sortable_group_column).

  3. Apply to a Model: Use the Sortable trait in your Eloquent model:

    use Rutorika\Sortable\Sortable;
    
    class Post extends Model
    {
        use Sortable;
    }
    

    This adds sortable() and sortableGroup() methods.

  4. First Use Case:

    • Sort a single model:
      $post = Post::find(1);
      $post->sortable()->move(2); // Move to position 2
      $post->save();
      
    • Grouped sorting (if using sortable_group_column):
      $post->sortableGroup()->move(1, 'group_id'); // Move within group_id
      
  5. Database Migration: Ensure your table has a sortable_column (default: sortable). Add it via migration:

    Schema::table('posts', function (Blueprint $table) {
        $table->integer('sortable')->default(0);
    });
    

Implementation Patterns

Core Workflows

  1. Basic Sorting:

    • Move a single item:
      $item->sortable()->move(5); // Move to position 5
      
    • Swap items:
      $item1->sortable()->swapWith($item2);
      
    • Get sorted collection:
      $sorted = Post::sorted()->get();
      
  2. Grouped Sorting:

    • Define sortable_group_column in config (e.g., category_id).
    • Sort within groups:
      $item->sortableGroup()->move(3, 'category_id');
      
    • Fetch sorted groups:
      $sortedGroups = Post::sortedGroup('category_id')->get();
      
  3. Many-to-Many Sorting:

    • Use sortableManyToMany() for pivot tables:
      class Tag extends Model
      {
          use Sortable;
      
          public function posts()
          {
              return $this->belongsToMany(Post::class)->withPivot('sortable');
          }
      }
      
    • Sort pivot records:
      $tag->posts()->sortableManyToMany()->move(1, $postId);
      
  4. Custom Columns: Override defaults in the model:

    class Post extends Model
    {
        use Sortable;
    
        protected $sortableColumn = 'custom_sort_order';
    }
    

Integration Tips

  • APIs: Use sortable() in API responses to ensure consistent ordering:
    return Post::sorted()->get()->sortBy('sortable');
    
  • Admin Panels: Integrate with packages like Backpack or Voyager for drag-and-drop UIs:
    // Example: Backpack CRUD sortable column
    CRUD::column('title', 'sortable')->sortable();
    
  • Observers: Trigger actions after sorting (e.g., cache updates):
    class PostObserver
    {
        public function saved(Post $post)
        {
            if ($post->wasChanged('sortable')) {
                Cache::forget('posts_sorted');
            }
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Database Locking:

    • Sorting operations may cause deadlocks if not handled carefully. Use transactions:
      DB::transaction(function () {
          $item->sortable()->move(1);
      });
      
    • Avoid sorting in bulk operations (e.g., update()) without transactions.
  2. Grouped Sorting Quirks:

    • If sortable_group_column is not set, grouped sorting will fail silently. Always validate:
      if (!$this->sortableGroupColumn) {
          throw new \RuntimeException('Group column not configured.');
      }
      
    • Ensure sortable_group_column has a default value in migrations to avoid NULL issues.
  3. Many-to-Many Pitfalls:

    • Pivot tables must include the sortable column. Example migration:
      Schema::create('post_tag', function (Blueprint $table) {
          $table->integer('sortable')->default(0);
      });
      
    • Detaching/reattaching items resets their sort order. Use sortableManyToMany()->detach() carefully.
  4. Performance:

    • Avoid sorted() on large datasets without pagination:
      // Bad: Loads all records
      $posts = Post::sorted()->get();
      
      // Good: Paginated
      $posts = Post::sorted()->paginate(20);
      
    • Index the sortable_column for better performance:
      Schema::table('posts', function (Blueprint $table) {
          $table->integer('sortable')->default(0);
      })->index('sortable');
      

Debugging

  1. Silent Failures:

    • Enable debug mode to catch issues:
      config(['sortable.debug' => true]);
      
    • Check logs for warnings like Sortable column not found.
  2. Race Conditions:

    • Use sortable()->lock() to prevent concurrent edits:
      $item->sortable()->lock()->move(3);
      
  3. Migration Errors:

    • If sortable column exists but is ignored, clear config cache:
      php artisan config:clear
      

Extension Points

  1. Custom Sort Logic: Override getSortableQuery() in your model:

    protected function getSortableQuery()
    {
        return $this->newQuery()->where('is_active', 1);
    }
    
  2. Events: Listen for sorting events:

    Sortable::sorting(function ($model, $position) {
        event(new SortingEvent($model, $position));
    });
    
  3. Validation: Add rules to ensure sortable values are within bounds:

    $validator = Validator::make($data, [
        'sortable' => 'integer|min:0|max:999',
    ]);
    
  4. Testing: Use SortableTestCase for assertions:

    $this->assertSorted($posts, [1, 2, 3]);
    
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.
nqxcode/phpmorphy
boundwize/pyrameter
testo/facade
headercat/phpstan-extension-ide-helper
yosymfony/parser-utils
innmind/black-box
babenkoivan/elastic-migrations
babenkoivan/elastic-adapter
sandermuller/package-boost-php
sandermuller/boost-core
develia/commons
dmstr/symfony-system-resources-bundle
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
renatomarinho/laravel-page-speed
develia/geo-bundle
austinheap/laravel-database-encryption
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle