Search code examples
laravellaravel-5pivotlaravel-5.3

Laravel: Formatting data from pivot table in template


In template I want to display product specifications like this:

Model
Brand: Asus
Interface
Interface: PCI Express 3.0
...

I tried adding another loop inside this foreach, but got errors:

foreach ($product->specifications as $specification) {
    echo $specification->name . '</br>';
    echo $specification->pivot->attribute . ': ' . $specification->pivot->value . '</br>';
}

Currently this outputs:

Model
Brand: Asus
Interface
Interface: PCI Express 3.0
Chipset
Chipset Manufacturer: AMD
Chipset
GPU: Radeon RX 470
Chipset
Core Clock: 1270 MHz in OC mode
Memory
Effective Memory Clock: 6600 MHz
Memory
Memory Size: 4GB
Memory
Memory Interface: 256-Bit
Memory
Memory Type: GDDR5

I need to display $specification->name only once and then all attributes and values under that type.

This is structure of pivot table:

public function up()
{
    Schema::create('product_specification', function (Blueprint $table) {
        $table->engine = 'InnoDB';

        $table->increments('id');
        $table->integer('product_id')->unsigned()->index();
        $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
        $table->integer('specification_id')->unsigned()->index();
        $table->foreign('specification_id')->references('id')->on('specifications')->onDelete('cascade');
        $table->string('attribute');
        $table->string('value');
    });
}

How could I achieve this? Should I change my table structure?


Solution

  • I think the best way to achieve this is with some post database processing.

    Take the following code.

    // Create a new collection
    $specifications = new Collection;
    
    // Loop through specifications
    foreach($product->specifications as $specification) {
        if (! $specifications->has($specification->name)) {
            // This is the first specification of this name
            $currentSpecs = new Collection;
        } else {
            // Other specifications have been entered
            $currentSpecs = $specifications->get($specification->name);
        }
    
        // Now we add the current spec to the list and set it on the main collection
        // Using the core name as the key
        $currentSpecs->put($specification->pivot->attribute, $specification->pivot->value);
        $specifications->put($specification->name, $currentSpecs);
    }
    

    Now in your template you can do the following.

    foreach($specifications as $name => $attributes) {
        echo $name;
        foreach($attributes as $attribute => $value) {
            echo $attribute .': '. $value;
        }
     }
    

    Obviously I've assumed that you don't need any of the ids or actual models, but this could very easily be adapted to work with that. You could also use the each method for the Collection class.

    Anyway, hope this helps.