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

Laravel Position Laravel Package

nevadskiy/laravel-position

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation: Run composer require nevadskiy/laravel-position and publish the migration with php artisan vendor:publish --provider="Nevadskiy\Position\PositionServiceProvider".
  2. Model Integration: Add the HasPosition trait to your Eloquent model (e.g., Category, MenuItem).
  3. Migration: Run the migration to add the position column (unsigned integer) to your table.
  4. First Use Case: Order a collection of models by position:
    $categories = Category::ordered()->get();
    

Key First Steps

  • Ordering: Use ordered() on a query builder to sort models by their position column.
  • Position Assignment: Assign positions via $model->position = 10; and save.
  • Validation: Ensure the position column is indexed for performance.

Implementation Patterns

Core Workflows

  1. Dynamic Positioning

    • Drag-and-Drop UIs: Use the position field to reorder items via AJAX (e.g., update position on sortablejs events).
    • Batch Updates: Update positions in bulk:
      Category::whereIn('id', [1, 2, 3])->updatePositions([10, 20, 30]);
      
  2. Query Integration

    • Default Ordering: Chain ordered() to any query:
      Category::whereActive(true)->ordered()->get();
      
    • Custom Order Logic: Combine with other query methods:
      Category::ordered()->limit(5)->get(); // Top 5 by position
      
  3. Position Management

    • Insertion Helpers: Use insertAtPosition($position) to place a new model at a specific rank:
      $newCategory = new Category(['name' => 'New']);
      $newCategory->insertAtPosition(5); // Insert at position 5
      
    • Gap Handling: Automatically adjust positions when inserting/deleting:
      $model->position = null; // Demote to end of list
      $model->save();
      
  4. API/Controller Patterns

    • Reorder Endpoint:
      public function updateOrder(Request $request) {
          $request->validate(['items' => 'required|array']);
          Category::updatePositions($request->items);
          return response()->json(['success' => true]);
      }
      
    • Frontend Integration: Return positions in API responses for client-side sorting:
      return Category::ordered()->get()->map(function ($item) {
          return ['id' => $item->id, 'name' => $item->name, 'position' => $item->position];
      });
      
  5. Admin Panel Integration

    • List Views: Display positions in admin tables (e.g., Laravel Nova or Filament):
      // Nova Tool Example
      public function fields(Request $request) {
          return [
              Text::make('Position', 'position'),
              // ... other fields
          ];
      }
      
    • Inline Editing: Allow position updates via inline forms.

Gotchas and Tips

Common Pitfalls

  1. Position Collisions

    • Issue: Duplicate positions can break ordering.
    • Fix: Use updatePositions() to auto-adjust gaps or validate uniqueness in migrations:
      $table->integer('position')->unique()->index();
      
    • Workaround: Manually handle conflicts in business logic.
  2. Performance with Large Datasets

    • Issue: Sorting millions of records by position can be slow.
    • Fix: Add a composite index if querying by position + other fields:
      Schema::table('categories', function (Blueprint $table) {
          $table->index(['position', 'name']);
      });
      
    • Tip: Use limit() or pagination to reduce query load.
  3. Transaction Conflicts

    • Issue: Concurrent updates to positions may cause race conditions.
    • Fix: Wrap updates in transactions:
      DB::transaction(function () {
          Category::updatePositions([10, 20, 30]);
      });
      
  4. Null Position Handling

    • Issue: Models with position = null may appear at the start/end unpredictably.
    • Fix: Explicitly handle nulls in queries:
      Category::ordered()->orderBy('position', 'asc')->get();
      
    • Tip: Use position = 0 for "unpositioned" items if needed.

Debugging Tips

  1. Query Inspection

    • Log the generated SQL to verify ordering:
      \DB::enableQueryLog();
      Category::ordered()->get();
      \Log::info(\DB::getQueryLog());
      
  2. Position Validation

    • Add a model observer to validate positions:
      public function saving(Category $category) {
          if ($category->position && $category->position < 0) {
              throw new \Exception('Position must be positive.');
          }
      }
      
  3. Migration Rollback

    • Issue: Forgetting to drop the position column during rollback.
    • Fix: Use reversible migrations or a custom rollback:
      public function down() {
          Schema::table('categories', function (Blueprint $table) {
              $table->dropColumn('position');
          });
      }
      

Extension Points

  1. Custom Position Logic

    • Override the getPositionAttribute or setPositionAttribute methods in your model:
      public function getPositionAttribute($value) {
          return $value ?: 9999; // Default to high value if null
      }
      
  2. Scope Customization

    • Extend the HasPosition trait to add custom scopes:
      public function scopeActiveOrdered($query) {
          return $query->whereActive(true)->ordered();
      }
      
  3. Event Hooks

    • Listen for position changes via model events:
      Category::updated(function ($category) {
          if ($category->isDirty('position')) {
              event(new PositionUpdated($category));
          }
      });
      
  4. Database-Level Triggers

    • For critical applications, use database triggers to enforce position rules (e.g., prevent negative values).
  5. Soft Deletes

    • Tip: If using soft deletes, ensure position updates respect deleted items:
      Category::withTrashed()->ordered()->get();
      
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle