Laravel saving liste des modèles éloquents commandés
je crée un menu alimentaire que l'administrateur peut commander/trier en glissant et en laissant tomber. Ce menu se compose de plusieurs catégories (catégorie de produits) et de Produits (Produit).
j'utilise HTML5Sortable sur le côté client pour permettre imbriquée d&d. Le balisage est assez simple:
<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>
Et le 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
}
La fonction getOrderedList
renvoie une chaîne JSON à Laravel, qui contient la catégorie triée id et l'id du produit:
{"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]}}
Comment faire pour que ça marche à l'arrière? Je suppose que je dois stocker ce tableau quelque part dans la base de données et plus tard trouver et commander les modèles par les id's?
en bref: Qu'est-ce qu'une solution propre et flexible pour trier (emboîter) les modèles (au sein de Laravel)?
2 réponses
Une convention commune est de Poids, ajouter un champ appelé (Int)Poids sur la table produits, qui est utilisé pour définir l'ordre des éléments.
une Fois qu'un changement dans l'ordre se produit, vous ne mettez à jour le champ de poids.
lorsque vous récupérez les articles, vous les Triez par poids.
il devient semblable à un Tableau
Id Name Weight
01 'product 1' 2
02 'product 2' 0
03 'product 3' 1
quand vous le commandez par poids vous obtenez
product 2
product 3
product 1
c'est similaire à un tableau parce que
$products[0] = 'product 2'
$products[1] = 'product 3'
$products[2] = 'product 1'
Notez que si vous souhaitez rendre encore plus dynamique, vous pouvez créer un polymorphe modèle qui peut satisfaire plusieurs modèles.
prière de consulter https://laravel.com/docs/5.1/eloquent-relationships#many-to-many-polymorphic-relations
Polymorphes Relations exemple
Create table Poids (exemple de migration)
$table->increments('id');
$table->integer('value');
$table->integer('weightable_id')->unsigned();
$table->string('weightable_type');
Créer un modèle Poids
class Weight extends Eloquent
{
public function weightable()
{
return $this->morphTo();
}
}
maintenant avec n'importe quel autre modèle
class Products extends Eloquent
{
...
public function weight()
{
return $this->morphOne(Weight::class);
}
}
de cette façon, vous pouvez simplement ajouter que la méthode à tous les modèles que vous voulez, alors vous pouvez trier votre modèle.
P.S. assurez-vous que tout modèle qui l'utilise, crée cette relation immédiatement après avoir créé le modèle
Je ne recommande pas cette méthode, il est beaucoup mieux si vous définissez explicitement le champ de poids dans la table des produits, je comprends combien vous voulez que votre code soit dynamique, mais tout vient à un coût
les performances diminuent, il n'est pas facile de visualiser votre code une fois que vous établissez des relations polymorphiques, c'est plus comme commencer à utiliser des sauts au lieu de fonctions
tout d'abord, le JSON que vous produisez ne devrait pas être un objet où les clés ne sont que des indices de tableaux. Au lieu de cela, il devrait être un tableau d'objets qui ressemble à ceci:
[{"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]}]
Depuis le products
tableau product_categories
table a une évidente plusieurs à une relation, vous devez juste utiliser le product_categories_id clé étrangère sur la products
table pour représenter les relations exposées dans votre JSON.
dans les objets imbriqués de votre JSON, chaque valeur de la produits le tableau de clés aura une clé étrangère qui correspond au id valeur clé dans le même objet imbriqué (c'est la product_category_id colonne products
tableau).
votre fonction de paramètre API ressemblerait alors à quelque chose comme ceci:
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']
));
}
}
je suis en train de mettre à jour le model directement dans le controller API ici, mais vous devriez vraiment faire toutes les modifications de model via un dépôt qui est aussi la mise en œuvre d'une interface.
ce qui précède fonctionnera si vous n'avez qu'un seul menu (avec ses catégories et produits). Si vous voulez plusieurs menus, puis vous aurez besoin d'un menus
table ainsi qu'une table à trois axes (avec colonnes menu_id
,product_id
et product_category_id
).