2016-01-03 31 views
12

Tworzę menu żywności, które administrator może zamówić/posortować, przeciągając i upuszczając. To menu składa się z wielu kategorii (ProductCategory) i produktów (Product).Laravel zapisuje uporządkowaną listę wymownych modeli

Używam HTML5Sortable po stronie klienta, aby umożliwić zagnieżdżone d & d. Znacznik jest dość prosta:

<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> 

i odpowiadająca 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 
} 

Funkcja getOrderedList wyśle ​​ciąg JSON z powrotem do laravel, który zawiera uporządkowany kategorię identyfikatora i identyfikator produktu:

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

Jak mogę to wykonać na zapleczu? Chyba muszę przechowywać tę tablicę gdzieś w bazie danych, a później znaleźć i zamówić modele według identyfikatorów?

W skrócie: Jakie jest czyste i elastyczne rozwiązanie do sortowania (zagnieżdżania) modeli (w ramach Laravel)?

Odpowiedz

5

Typową konwencją jest Waga, dodać pole o nazwie (Int) Wagi w tabeli produktów, która służy do określenia kolejności pozycji.

Po zmianie kolejności zaktualizujesz tylko pole wagi.

Po odzyskaniu przedmiotów sortowane są według wagi.

staje się podobna do tablicy

Id  Name   Weight 
01  'product 1'  2 
02  'product 2'  0 
03  'product 3'  1 

kiedy zamówienie wagowych masz

product 2 
product 3 
product 1 

jest podobny do tablicy, ponieważ

$products[0] = 'product 2' 
$products[1] = 'product 3' 
$products[2] = 'product 1' 

Pamiętaj, że jeśli chcesz aby było jeszcze bardziej dynamiczne, możesz stworzyć pol ymorficzny model, który może spełniać wiele modeli.

Proszę odnieść się do https://laravel.com/docs/5.1/eloquent-relationships#many-to-many-polymorphic-relations przykład

polimorficzne Relations

Tworzenie tabeli Wagi (np migracja)

$table->increments('id'); 
$table->integer('value'); 
$table->integer('weightable_id')->unsigned(); 
$table->string('weightable_type'); 

Tworzenie modelu Waga

class Weight extends Eloquent 
{ 
    public function weightable() 
    { 
     return $this->morphTo(); 
    } 
} 

teraz z żadnym innym modelu

class Products extends Eloquent 
{ 
    ... 
    public function weight() 
    { 
     return $this->morphOne(Weight::class); 
    } 
} 

ten sposób można tylko dodać, że sposób do dowolnego modelu chcesz, to możesz uporządkować swój model z nim.

P.S.upewnij się, że każdy model, który go używa, tworzy tę relację natychmiast po utworzeniu modelu, nie polecam tej metody, jest znacznie lepiej, jeśli jawnie zdefiniujesz pole wagi w tabeli Produkty, rozumiem, ile chcesz Twój kod być dynamiczne, ale wszystko jest w cenie

wydajność idzie w dół, nie jest łatwo wizualizować swój kod po nawiązać stosunki polimorficzne, jego bardziej jak rozpoczęciem użytkowania skoki zamiast funkcji

+0

Dziękuję za odpowiedź, ale już to wiedziałem. Chyba szukam rozwiązania polimorficznego, w którym kolumna "Waga" nie byłaby przechowywana w samym modelu produktu, więc dziękuję za wskazanie tego. – JasonK

+0

Będę edytować odpowiedź, aby uwzględnić rozwiązanie polimorficzne w nieco –

2

Najpierw JSON, który produkujesz nie powinien być obiektem, w którym klucze są tylko indeksami tablicowymi. Zamiast tego powinna być tablicą obiektów, które wygląda następująco:

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

Ponieważ products stół do product_categories tabela ma oczywisty wiele do jednego związku, że wystarczy użyć product_categories_id klucz obcy w tabeli products do reprezentowania relacji określonych w twoim JSON.

W zagnieżdżonych obiektów swojej JSON, każda wartość w produktów klucz tablica będzie mieć klucz obcy, która odpowiada wartości klucza w tym samym zagnieżdżonego obiektu (jest to product_category_id kolumnę na id swoje products stół).

Twoja funkcja końcowym API będzie wtedy wyglądać tak:

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'] 
     )); 
    } 

} 

ja aktualizacją modelu bezpośrednio w kontrolerze API tutaj, ale naprawdę należy zrobić każdy model zmian poprzez repozytorium, który jest również wykonawczych interfejs .

Powyższe działa, jeśli masz tylko jedno menu (z jego kategoriami i produktami). Jeśli chcesz mieć wiele menu, musisz mieć tabelę menus wraz z trójstronną tabelą przestawną (z kolumnami menu_id, product_id i product_category_id).

+0

Aktualizujesz "category_id" w modelu produktu, nie widzę jak to się odnosi do mojego "sortowalnego" pytania. – JasonK

+0

@JasonK Pytasz, jak zapisać kombinację produktów i kategorii, które wybierze użytkownik. Jeśli zadajesz inne pytanie, powinieneś naprawdę przejść i zmodyfikować sposób sformułowania swojego pytania –