Подтвердить что ты не робот

Laravel сохраняет упорядоченный список красноречивых моделей

Я создаю меню продуктов, которое администратор может заказать/сортировать, перетаскивая его. Это меню состоит из нескольких категорий (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, которая содержит идентификатор отсортированной категории и идентификатор продукта:

{"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]}}

Как мне сделать эту работу в фоновом режиме? Думаю, я должен хранить этот массив где-то в базе данных, а затем найти и заказать модели по идентификаторам?

Вкратце: что такое чистое и гибкое решение для сортировки (вложенных) моделей (внутри Laravel)?

4b9b3361

Ответ 1

Общим соглашением является "Вес", добавьте поле "Int" Weight в таблицу продуктов, которое используется для определения порядка элементов.

Как только произойдет изменение порядка, вы обновите только поле веса.

Когда вы извлекаете элементы, вы сортируете их по весу.

он становится похожим на Array

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, я понимаю, насколько вы хотите, чтобы ваш код был динамичным, но все идет за счет стоимости

Производительность снижается, вам нелегко визуализировать ваш код, как только вы устанавливаете полиморфные отношения, тем больше он начинает использовать переходы вместо функций

Ответ 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 имеет очевидное отношение к одному, вы просто используете внешний ключ product_categories_id в таблице products для представления отношений, изложенных в вашем JSON.

Во вложенных объектах вашего JSON каждое значение в массиве ключей продукта будет иметь внешний ключ, соответствующий значению ключа id в том же вложенном объекте (это столбец product_category_id в таблице products).

Ваша конечная точка 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).

Ответ 3

Я просто реализую это поведение с помощью этой библиотеки: https://github.com/spatie/eloquent-sortable

Это очень просто реализовать, в основном вам нужен дополнительный столбец, чтобы сохранить порядок, а библиотека сделает все остальное, вот часть документации:

  • Реализуйте интерфейс Spatie\EloquentSortable\Sortable.
  • Используйте черту Spatie\EloquentSortable\SortableTrait.
  • При желании укажите, какой столбец будет использоваться в качестве столбца заказа. Значением по умолчанию является order_column.

использовать Spatie\EloquentSortable\Sortable; использовать Spatie\EloquentSortable\SortableTrait;

класс MyModel расширяет возможности Eloquent Sortable {

use SortableTrait;

public $sortable = [
    'order_column_name' => 'order_column',
    'sort_when_creating' => true,
];

...
}