arneetsingh/laravel-customsort

A package to manually sort records of a eloquent model in custom order

1.0.0 2022-05-19 15:19 UTC

README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

Problem it solves:

Say there is a need to show certain records of posts, eg. featured posts on top in your listing page. Just a custom order set by user to show specific posts in a specific order on top.

Installation

You can install the package via composer:

composer require arneetsingh/laravel-customsort

Publish and run the migrations with:

php artisan vendor:publish --tag="laravel-customsort-migrations"
php artisan migrate

You can publish the config file with:

php artisan vendor:publish --tag="laravel-customsort-config"

Usage

Model

Use the CanCustomSort trait in your model you want to have the ability of sorting manually.

<?php

namespace App\Models;

use ArneetSingh\CustomSort\Traits\CanCustomSort;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use CanCustomSort;
}

Setting the order

Lets say we have 5 posts in our Post model. and we want to set them in order of ids - 2,4,1,5,3

Post::setNewOrder([2, 4, 1, 5, 3]);

Do note you don't need to pass all of your posts, you can though. Just the ones passed will be returned on top in that order.

Fetching in Custom Order

Post::orderByCustom()->get();

Will return post in order set first, and then rest of posts.

Set Priority per model basis

$post->setOrderPriority(10);

If the priority no is higher than other posts, it will be moved to top in results.

Example

Lets say we have 5 posts in our Post model. and we want to set them in order of ids - 2,4,1,5,3

Request: PUT
Endpoint: /posts/customSort
Payload:
{
	"custom_sort":[
		{
			"id":2,
			"priority":5			
		},
		{
			"id":4,
			"priority":4			
		},
		{
			"id":1,
			"priority":3			
		},
		{
			"id":5,
			"priority":2			
		},
		{
			"id":3,
			"priority":1			
		}
	]
}

Controller code could look like

    public function store(Request $request)
    {
        $request->validate([
            'custom_sort' => 'required',
            'custom_sort.*.id' => "required|exists:posts,id",
            'custom_sort.*.priority' => 'required|integer'
        ]);
        
        $morphClass = (new Post())->customSort()->getMorphClass();
        collect($request->custom_sort)->transform(function ($item) use($morphClass) {
            CustomSort::create([
                'sortable_id' => $item['id'],
                'sortable_type' => $morphClass,
                'priority' => $item['priority']
            ]);
        });
    }

68747470733a2f2f692e696d6775722e636f6d2f39554d6563567a2e676966

Frontend Tips

I used SortabelJS for having the ability to drag and drop to set manual order. And here is snippet to javascript code.

let posts = []

// SortableJS onEnd handler would look like this
onEnd: function ({ oldIndex, newIndex }){
  const movedItem = posts.splice(oldIndex, 1)[0]
  posts.splice(newIndex, 0, movedItem)
}

// prepare payload
preparePayload: function() {
  const order = posts.map((item, key) => {
    return {
      id: item.id,
      priority: posts.length - key
    }
  })
  return { custom_sort: order }
}

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.