svv-team / sortable
为 Laravel Eloquent 模型添加可排序行为和排序。支持分组和一对多。
Requires
- php: >=7.2.5
- illuminate/support: ^7.0
Requires (Dev)
This package is not auto-updated.
Last update: 2024-09-24 15:59:22 UTC
README
Laravel 5 - 示例
https://github.com/boxfrommars/rutorika-sortable-demo5
安装
通过 Composer 安装包
composer require rutorika/sortable
版本兼容性
可排序特征
为 Eloquent (Laravel) 模型添加可排序行为
用法
将 position 字段添加到您的模型中(以下是如何更改此名称的示例)
// schema builder example public function up() { Schema::create('articles', function (Blueprint $table) { // ... other fields ... $table->integer('position'); // Your model must have position field: }); }
将 \Rutorika\Sortable\SortableTrait 添加到您的 Eloquent 模型。
class Article extends Model { use \Rutorika\Sortable\SortableTrait; }
如果您想使用自定义列名作为位置,设置 $sortableField
class Article extends Model { use \Rutorika\Sortable\SortableTrait; protected static $sortableField = 'somefield'; }
现在您可以使用 moveBefore($entity) 和 moveAfter($entity) 方法移动您的实体(之后您不需要保存模型,它已经保存了)
$entity = Article::find(1); $positionEntity = Article::find(10) $entity->moveAfter($positionEntity); // if $positionEntity->position is 14, then $entity->position is 15 now
此外,此特征会自动在 create 事件上定义实体位置,因此您无需手动添加 position,只需像往常一样创建实体即可
$article = new Article(); $article->title = $faker->sentence(2); $article->description = $faker->paragraph(); $article->save();
此实体将位于 entitiesMaximumPosition + 1 位置
要获取排序后的实体,请使用 sorted 范围
$articles = Article::sorted()->get();
**注意**:删除记录后不会重新排序。位置值中的间隔不会影响您的列表排序。但是,如果您希望防止间隔,可以使用
deleting事件重新定位您的模型。例如
// YourAppServiceProvider YourModel::deleting(function ($model) { $model->next()->decrement('position'); });
您需要 rutorika-sortable >=2.3 才能使用
->next()
可排序分组
如果您想按字段对实体进行分组排序,请将以下内容添加到您的模型中
protected static $sortableGroupField = 'fieldName';
现在移动和排序将封装在此字段中。
如果您想按多个字段对实体进行分组排序,请使用数组
protected static $sortableGroupField = ['fieldName1','fieldName2'];
可排序一对多
假设您的数据库结构如下
posts
id
title
tags
id
title
post_tag
post_id
tag_id
并且您想为每个 post 排序 tags
将 position 列添加到关联表中(您可以使用任何名称,但默认使用 position)
post_tag
post_id
tag_id
position
将 \Rutorika\Sortable\BelongsToSortedManyTrait 添加到您的 Post 模型,并定义由此特征提供的 belongsToSortedMany 关系
class Post extends Model { use BelongsToSortedManyTrait; public function tags() { return $this->belongsToSortedMany('\App\Tag'); } }
注意:
$this->belongsToSortedMany与$this->belongsToMany的签名不同 -- 此方法的第二个参数是$orderColumn(默认为'position'),其他参数相同
使用 save/sync/attach 方法附加标签到帖子将设置正确位置
$post->tags()->save($tag) // or $post->tags()->attach($tag->id) // or $post->tags()->sync([$tagId1, $tagId2, /* ...tagIds */])
获取相关模型时将按位置排序
$post->tags; // ordered by position by default
您可以重新排序给定帖子的标签
$post->tags()->moveBefore($entityToMove, $whereToMoveEntity); // or $post->tags()->moveAfter($entityToMove, $whereToMoveEntity);
一对多示例:http://sortable5.boxfrommars.ru/posts (代码)
您还可以通过使用 MorphsToSortedManyTrait 特征并从关系方法返回 $this->morphToSortedMany() 来使用可排序行为的多态一对多关系。
根据 Laravel 多态一对多表关系,您的表应如下所示
posts
id
title
tags
id
title
taggables
tag_id
position
taggable_id
taggable_type
并且您的模型如下所示
class Post extends Model { use MorphToSortedManyTrait; public function tags() { return $this->morphToSortedMany('\App\Tag', 'taggable'); } }
可排序控制器
此外,此包还提供了 \Rutorika\Sortable\SortableController,它处理对排序实体的请求
用法
将服务提供者添加到 config/app.php
'providers' => array( // providers... 'Rutorika\Sortable\SortableServiceProvider', )
发布配置
php artisan vendor:publish
在配置 config/sortable.php 中添加您需要排序的模型
'entities' => array( 'articles' => '\App\Article', // entityNameForUseInRequest => ModelName // or 'articles' => ['entity' => '\App\Article'], // or for many to many 'posts' => [ 'entity' => '\App\Post', 'relation' => 'tags' // relation name (method name which returns $this->belongsToSortedMany) ] ),
将路由添加到控制器的 sort 方法
Route::post('sort', '\Rutorika\Sortable\SortableController@sort');
现在如果您向此路由发送有效数据
$validator = \Validator::make(\Input::all(), array( 'type' => array('required', 'in:moveAfter,moveBefore'), // type of move, moveAfter or moveBefore 'entityName' => array('required', 'in:' . implode(',', array_keys($sortableEntities))), // entity name, 'articles' in this example 'positionEntityId' => 'required|numeric', // id of relative entity 'id' => 'required|numeric', // entity id )); // or for many to many $validator = \Validator::make(\Input::all(), array( 'type' => array('required', 'in:moveAfter,moveBefore'), // type of move, moveAfter or moveBefore 'entityName' => array('required', 'in:' . implode(',', array_keys($sortableEntities))), // entity name, 'articles' in this example 'positionEntityId' => 'required|numeric', // id of relative entity 'id' => 'required|numeric', // entity id 'parentId' => 'required|numeric', // parent entity id ));
则具有 \Input::get('id') id 的实体将与具有 \Input::get('positionEntityId') id 的实体相对移动。
例如,如果请求数据为
type:moveAfter
entityName:articles
id:3
positionEntityId:14
则 id 为 3 的文章将移动到 id 为 14 的文章之后。
jQuery UI sortable 示例
注意:Laravel 5 默认启用了 csrf 中间件,因此您应该设置ajax请求: https://laravel.net.cn/docs/5.0/routing#csrf-protection
模板
<table class="table table-striped table-hover"> <tbody class="sortable" data-entityname="articles"> @foreach ($articles as $article) <tr data-itemId="{{{ $article->id }}}"> <td class="sortable-handle"><span class="glyphicon glyphicon-sort"></span></td> <td class="id-column">{{{ $article->id }}}</td> <td>{{{ $article->title }}}</td> </tr> @endforeach </tbody> </table>
多对多排序的模板
<table class="table table-striped table-hover"> <tbody class="sortable" data-entityname="posts"> @foreach ($post->tags as $tag) <tr data-itemId="{{ $tag->id }}" data-parentId="{{ $post->id }}"> <td class="sortable-handle"><span class="glyphicon glyphicon-sort"></span></td> <td class="id-column">{{ $tag->id }}</td> <td>{{ $tag->title }}</td> </tr> @endforeach </tbody> </table>
/** * * @param type string 'insertAfter' or 'insertBefore' * @param entityName * @param id * @param positionId */ var changePosition = function(requestData){ $.ajax({ 'url': '/sort', 'type': 'POST', 'data': requestData, 'success': function(data) { if (data.success) { console.log('Saved!'); } else { console.error(data.errors); } }, 'error': function(){ console.error('Something wrong!'); } }); }; $(document).ready(function(){ var $sortableTable = $('.sortable'); if ($sortableTable.length > 0) { $sortableTable.sortable({ handle: '.sortable-handle', axis: 'y', update: function(a, b){ var entityName = $(this).data('entityname'); var $sorted = b.item; var $previous = $sorted.prev(); var $next = $sorted.next(); if ($previous.length > 0) { changePosition({ parentId: $sorted.data('parentid'), type: 'moveAfter', entityName: entityName, id: $sorted.data('itemid'), positionEntityId: $previous.data('itemid') }); } else if ($next.length > 0) { changePosition({ parentId: $sorted.data('parentid'), type: 'moveBefore', entityName: entityName, id: $sorted.data('itemid'), positionEntityId: $next.data('itemid') }); } else { console.error('Something wrong!'); } }, cursor: "move" }); } });
开发
sudo docker build -t rutorika-sortable .
sudo docker run --volume $PWD:/project --rm --interactive --tty --user $(id -u):$(id -g) rutorika-sortable vendor/bin/phpunit