2016-02-03 7 views
13

voglio fare un elenco con tutti i prodotti disponibili e l'importo per dimensioni comelaravel ottenere quantità dimensioni, se non esiste 0

name  | size1 | size2 | size 3 | size4 | total 
________________________________________________________ 
t-shirt1 | 0 | 1 | 3 | 9 | 13 
t-shirt2 | 3 | 1 | 1 | 9 | 14 
t-shirt3 | 0 | 0 | 0 | 0 | 0 

Il mio modello Product ha una relazione con ProductSize come:

public function sizeAvailable(){ 
    return $this->hasMany('App\ProductSize'); 

} 

mio ProductSize ha una relazione con Product come:

public function product() 
{ 
    return $this->belongsTo('App\Product'); 
} 

mio productSize ha una relazione con Size come:

public function size(){ 
    return $this->belongsTo('App\Size'); 
} 

Il modello Productsize contiene un valore per importo. Quindi sono in grado di ottenere tutte le taglie per un prodotto con la giusta quantità, e sono anche in grado di ottenere tutti i prodotti da una dimensione. Come posso creare la lista come nel mio esempio. È possibile utilizzare la dimensione come indice? così ho potuto fare (pseudo codice) per riempire le <td> tag:

for(all products) 
{ 
    if(product[somesize] not null) 
     {{ product[somesize]->amount }} 
    else 
     0 
} 

Il problema che ho è che non so come impostare la quantità nel <tr> alla tabella se v'è ad esempio 1 formato (size3) e nessun altro quando faccio $product->sizeAvailable() conterrà solo 1 valore (size3), quindi devo inserire 0 in size1 ma come posso verificare se size1 non è disponibile per il prodotto? O c'è un modo migliore per riempire gli importi delle dimensioni del tavolo?

Quello che ho attualmente:

<table id="myTable" class="tablesorter table table-striped table-responsive"> 
     <thead> 
     <tr> 
      <th> 
       Product 
      </th> 
      @foreach($sizes as $size) 
       <th> 
        {{ $size->name }} 
       </th> 
      @endforeach 
     </tr> 
     </thead> 
     <tbody> 

      @foreach($products as $product) 
       <tr > 
        <td> 
         {{ucfirst($product->name)}} 
        </td> 
        @foreach($sizes as $size) 
         <td> 
          HERE I NEED TO DO A CHECK IF $product HAS $size RETURN 0 ELSE RETURN ProductSize->amount 
         </td> 
        @endforeach 



       </tr> 
      @endforeach 

     </tbody> 
    </table> 

ho potuto fare una funzione in modello del prodotto simile:

hasSize($size) 
{ 
    $result = select from ProductSize where size = $size 

    if ($result = null) 
     return 0; 

    return $result->amount(); 
} 

Ma con questa soluzione devo eseguire una query products * sizes volte, se ho 1000 prodotti e 20 taglie, pari a 20.000 querys per un tavolo.

+0

Ti sei divertito con gli aggregati ([qui] (https://laravel.com/docs/5.2/eloquent#retrieving-aggregates) e [qui] (https://laravel.com/docs/5.2/query # ordering-grouping-limit-and-offset)) per questo problema Sven? – Theson

+0

Devo ammettere che anche un join SQL o anche una vista basata su questo sarebbe stato un buon adattamento - ho comunque provato a fornire una soluzione all-Laravel per mostrare quanto lontano può andare. – luchaos

+1

è il 'Dati del database pertinente' nella parte inferiore completa? hai menzionato che il modello ProductSizes contiene un valore per 'amount' - anche la tabella' product_sizes' ha questa colonna? – luchaos

risposta

7

Hai costruito manualmente un Many to Many Relationship per il quale Laravel fornisce già diversi utili caratteristiche:

1. modello di aggiornamento del prodotto (aggiungere o sostituire relazione esistente):

public function sizes() 
{ 
    // many to many relation with intermediate table column 
    return $this->belongsToMany('App\Size', 'product_sizes')->withPivot('amount'); 
} 

public function getTotalAttribute() 
{ 
    // access pivot table directly and use sum aggregate 
    return DB::table('product_sizes')->where('product_id', $this->attributes['id'])->sum('amount'); 
} 

2.Recupera modelli (nel controllore) in questo modo: modello

$sizes = Size::all(); 
$products = Product::with('sizes')->get(); // eager load sizes 

3. lama:

... 
<td> 
    {{ucfirst($product->name)}} 
</td> 
@foreach($sizes as $size) 
<td> 
    {{-- HERE I NEED TO DO A CHECK IF $product HAS $size RETURN 0 ELSE RETURN ProductSize->amount --}} 
    {{-- check and retrieve by using Collection methods --}} 
    {{ $product->sizes->contains($size) ? $product->sizes->find($size)->pivot->amount : 0 }} 
</td> 
@endforeach 
<td>{{ $product->total }}</td> 
.... 

Dopo ricreare il tuo esempio con le modifiche di cui sopra e un (molto piccola) di semi di database Ottengo:

Product  size1 size2 size3 total 
T-shirt1 10  3  0  13 
T-shirt2 5  0  0  5 

  • Per impostazione predefinita questa soluzione produce solo 3 query a causa di eager loading. (Verificare con DebugBar) Ogni calcolo total aggiunge una query (sfortunatamente il generatore di query di Laravel non ha aggregate methods per le tabelle pivot).

  • e find() nella vista attraversa le raccolte precaricate - nessuna query aggiuntiva qui.

  • Non è necessario il modello ProductSize in quanto contiene solo una tabella pivot con un attributo aggiuntivo (amount). Vedi Many to Many relationships and retrieving intermediate table columns.

  • Per comodità: se la tabella product_sizes viene rinominato product_size e consegue convenzione tabella di denominazione di laravel il secondo parametro di $this->belongsToMany('App\Size', 'product_sizes') non è necessaria e può essere scritta in questo modo: $this->belongsToMany('App\Size')

Il [ tabella product_size] è derivata dall'ordine alfabetico dei relativi nomi di modello.

+0

@ qualcuno: fornire un commento costruttivo se il voto diminuisce come suggerito da SO - non ha molto senso senza di esso. – luchaos

1

Non uso la struttura del tavolo perché non conosco la costruzione esatta ma faccio per voi un esempio.

Io uso solo 2 queryes e non 20 000

Provatelo, rendere nuova l'utilizzo del database scaricare

discarica SQL

# Host: localhost (Version: 5.5.25) 
    # Date: 2002-01-01 01:34:00 
    # Generator: MySQL-Front 5.3 (Build 4.81) 

    /*!40101 SET NAMES utf8 */; 

    # 
    # Structure for table "products" 
    # 

    DROP TABLE IF EXISTS `products`; 
    CREATE TABLE `products` (
    `product_id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`product_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; 

    # 
    # Data for table "products" 
    # 

    INSERT INTO `products` VALUES (1,'iphone'),(2,'Ls'),(3,'Samsung'); 

    # 
    # Structure for table "size_name" 
    # 

    DROP TABLE IF EXISTS `size_name`; 
    CREATE TABLE `size_name` (
    `Id` int(11) NOT NULL AUTO_INCREMENT, 
    `size_id` varchar(255) DEFAULT NULL, 
    `product_id` varchar(255) DEFAULT NULL, 
    `name` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`Id`) 
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; 

    # 
    # Data for table "size_name" 
    # 

    INSERT INTO `size_name` VALUES (1,'1','2','color'),(2,'2','1','width'),(3,'3','3','height'),(6,'3','2','color'),(7,'2','3','width'),(8,'1','1','height'),(9,'1','3','color'),(10,'2','2','width'),(11,'3','1','height'); 

    # 
    # Structure for table "size_value" 
    # 

    DROP TABLE IF EXISTS `size_value`; 
    CREATE TABLE `size_value` (
    `Id` int(11) NOT NULL AUTO_INCREMENT, 
    `value_name` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`Id`) 
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; 

    # 
    # Data for table "size_value" 
    # 

    INSERT INTO `size_value` VALUES (1,''),(2,'bluen'),(3,'green'),(5,'type2'),(6,'type3'),(7,'type4'); 

E ora PHP

<?php 
    $bd_host="localhost"; 
    $bd_user="root"; 
    $bd_password=""; 
    $bd_base="newdatabase2"; 
    $con=mysql_connect($bd_host, $bd_user, $bd_password); 
    if(!con) { echo 'error.'; exit; } 
    mysql_select_db($bd_base, $con); 
    mysql_query('SET NAMES utf8'); 
    /* query1 get table rows caption */ 
    $q="select * from size_name group by size_id"; 
    $res=mysql_query($q); 
    while($row=mysql_fetch_assoc($res)) { 
    $caption[$row['id']]=$row['name']; 
    } 
    // I limit to 3 products but you can change here, make loop 
    $prod1='1'; 
    $prod2='2'; 
    $prod3='3'; 
    //here you need to change to work with all products 
    $where=" where size_name.product_id='$prod1' or size_name.product_id='$prod2' or size_name.product_id='$prod3' "; 
    /* query2 select size for your example */ 
    $q="select * from size_name left join (size_value) on (size_name.id=size_value.id) $where order by size_id, product_id"; 
    $res=mysql_query($q); 
    while($row=mysql_fetch_array($res)) { 
    if(!isset($id) || $id<>$row['size_id']) $id=$row['size_id']; 

    /**/ 
    /* here nedd to make loop for all products youu need, I do for only 3 products */ 
    /**/ 
    /**/ 
    /*#1*/ 
    if($row['product_id']==$prod1) $characteristics1[$prod1][$id]=$row['value_name']; else 
    /*#2*/ 
    if($row['product_id']==$prod2) $characteristics2[$prod2][$id]=$row['value_name']; else 
    /*#3*/ 
    if($row['product_id']==$prod3) $characteristics3[$prod3][$id]=$row['value_name']; 
    /**/ 
    /**/ 
    } 
    ?> 
    <table style="width:80%;border-spacing:0; text-align:center;"> 
    <tr style="background-color:purple;color:#FFF;"> 
    <td style="background-color:yellow; color:#999;"></td> 
    <td>Product 1</td> 
    <td>Product 2</td> 
    <td>Product 3</td> 
    </tr> 
    <? 
    foreach($caption as $key => $value) { ?> 
    <tr> 
    <td style="background-color:yellow;width:20%;"><? echo $caption[$key]; ?></td> 
    <td style="width:20%;"><? if($characteristics1[$prod1][$key]!='') echo $characteristics1[$prod1][$key]; else echo ' 0 '; ?></td> 
    <td style="width:20%;"><? if($characteristics2[$prod2][$key]!='') echo $characteristics2[$prod2][$key]; else echo ' 0 '; ?></td> 
    <td style="width:20%;"><? if($characteristics3[$prod3][$key]!='') echo $characteristics3[$prod3][$key]; else echo ' 0 '; ?></td> 
    <? 
    } ?> 
    </tr></table>