我正在创建一个食物菜单,管理员可以通过拖放来订购/排序。此菜单包含多个类别(ProductCategory)和产品(Product)。
我在客户端使用HTML5Sortable来允许嵌套d& d。标记非常简单:
<div class="categories">
@foreach($categories as $category)
<div class="category">
@foreach($category->products as $product)
<div class="products">
<div class=""product" data=id="{{ $product->id }}">
{{ $product->name }}
</div>
</div><!-- /products !-->
@endforeach
</div><!-- /category !-->
@endforeach
</div>
和相应的javascript:
$('.categories').sortable({
items: '.category'
});
$('.products').sortable({
items: '.product'
});
// Will be called when the user is done repositioning the products and categories
function getOrderedList() {
var data = {};
$('.categories').find('.category').map(function(i) {
var category = $(this);
data[i] = {};
data[i].id = category.data('id');
data[i].products = category.find('.product').map(function() {
return $(this).data('id');
}).get();
});
data = JSON.stringify(data); // Send data to server
}
函数getOrderedList
将JSON字符串发送回Laravel,其中包含已排序的类别ID和产品ID:
{"0":{"id":1,"products":[2,3,1,4,5,6,7,8,9,10]},"1":{"id":2,"products":[11,12,13,14]},"2":{"id":3,"products":[15,16,17,18]}}
我如何在后端进行此项工作?我想我必须将这个数组存储在数据库的某个地方,然后通过id找到并订购模型?
简而言之:什么是排序(嵌套)模型的清洁灵活的解决方案(在Laravel中)?
答案 0 :(得分:6)
常见的约定是权重,在产品表上添加一个名为(Int)Weight的字段,用于定义项目的顺序。
一旦订单发生变化,您只需更新权重字段。
检索项目时,按重量对其进行排序。
它变得类似于数组
Id Name Weight
01 'product 1' 2
02 'product 2' 0
03 'product 3' 1
当你按重量订购时,你会得到
product 2
product 3
product 1
它类似于数组,因为
$products[0] = 'product 2'
$products[1] = 'product 3'
$products[2] = 'product 1'
请注意,如果您想要使其更加动态,您可以创建一个可以满足多个模型的多态模型。
请参阅https://laravel.com/docs/5.1/eloquent-relationships#many-to-many-polymorphic-relations
多态关系示例
创建表权重(迁移示例)
$table->increments('id');
$table->integer('value');
$table->integer('weightable_id')->unsigned();
$table->string('weightable_type');
创建模型重量
class Weight extends Eloquent
{
public function weightable()
{
return $this->morphTo();
}
}
现在使用任何其他模型
class Products extends Eloquent
{
...
public function weight()
{
return $this->morphOne(Weight::class);
}
}
通过这种方式,您可以将该方法添加到您想要的任何模型中,然后就可以使用它对模型进行排序。
<强> P.S。确保使用它的任何模型在创建模型后立即创建该关系
我不推荐这种方法,如果你明确定义Products表中的权重字段会更好,我知道你希望你的代码有多大动态,但一切都需要付出代价
性能下降,一旦建立多态关系就不容易想象您的代码,更像是开始使用Jumps而不是函数
答案 1 :(得分:2)
首先,您生成的JSON不应该是键只是数组索引的对象。相反,它应该是一个对象数组,如下所示:
[{"id":1,"products":[2,3,1,4,5,6,7,8,9,10]},{"id":2,"products":[11,12,13,14]},{"id":3,"products":[15,16,17,18]}]
由于products
表到product_categories
表具有明显的多对一关系,因此您只需使用products
表上的 product_categories_id 外键表示JSON中列出的关系。
在JSON的嵌套对象中, products 键数组中的每个值都将具有与同一嵌套对象中 id 键值对应的外键(这是products
表上的 product_category_id 列。
您的API端点函数将如下所示:
public function myApiEndpoint(){
$input = Input::get('input');
$input = json_decode($input, true);
foreach($input as $category){
Product::whereIn('id', $category['products'])->update(array(
'product_category_id' => $category['id']
));
}
}
我在这里直接在API控制器中更新模型,但您应该通过同时实现接口的存储库进行任何模型更改。
如果你只有一个菜单(带有它的类别和产品),上面的方法就可以了。如果您需要多个菜单,那么您需要一个menus
表以及一个三向数据透视表(包含menu_id
,product_id
和product_category_id
列。
答案 2 :(得分:0)
我只是使用此库实现此行为: https://github.com/spatie/eloquent-sortable
实现非常简单,基本上,您需要一个额外的列来保持顺序,而库将完成其余工作,这是文档的一部分:
使用Spatie \ EloquentSortable \ Sortable; 使用Spatie \ EloquentSortable \ SortableTrait;
Class MyModel扩展了Eloquent实现的Sortable {
use SortableTrait;
public $sortable = [
'order_column_name' => 'order_column',
'sort_when_creating' => true,
];
...
}