alexcrawford / lexorank-sortable
为 Laravel Eloquent 模型添加可排序行为和排序。支持分组和多对多。
Requires
- php: >=7.2.5
- alexcrawford/lexorank-php: ^1.0
- laravel/framework: *
Requires (Dev)
This package is auto-updated.
Last update: 2024-08-29 05:43:17 UTC
README
通过 Composer 安装包
composer require alexcrawford/lexorank-sortable
版本兼容性
可排序特性
为 Eloquent (Laravel) 模型添加可排序行为
用法
将 position
字段添加到您的模型中(以下是如何更改此名称的示例)
// schema builder example public function up() { Schema::create('articles', function (Blueprint $table) { // ... other fields ... $table->string('position'); // Your model must have position field: }); }
将 \AlexCrawford\Sortable\SortableTrait
添加到您的 Eloquent 模型中。
class Article extends Model { use \AlexCrawford\Sortable\SortableTrait; }
如果您想使用自定义列名作为位置,设置 $sortableField
class Article extends Model { use \AlexCrawford\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 aaa, then $entity->position is aab 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'); });
您需要 alexcrawford-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
将 \AlexCrawford\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'); } }
可排序控制器
此外,此包还提供了 \AlexCrawford\Sortable\SortableController
,用于处理对实体排序的请求
用法
将服务提供程序添加到 config/app.php
'providers' => array( // providers... 'AlexCrawford\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', '\AlexCrawford\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 alexcrawford-sortable .
sudo docker run --volume $PWD:/project --rm --interactive --tty --user $(id -u):$(id -g) alexcrawford-sortable vendor/bin/phpunit