Arnachap
Arnachap

Reputation: 1

Merge two collections in Laravel and access it

Ok, so here is my problem : I have'nt found a proper solution to 'merge' (not sure if it is the right word for it) two collections in laravel. I'll show you my code, it'll explains itself.

So here is my crappy way-arround code, but I'm pretty sure there is a better way to do it :

Here is my controller :

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Product;
use App\ProductPhoto;

class ProductController extends Controller
{
    public function index() {
        $products = Product::all();
        $photos = ProductPhoto::all();

        return view('/products')->with([
            'products' => $products,
            'photos' => $photos
        ]);
    }
}

and my view looks like this ;

@foreach($products as $product)
    @foreach($photos as $photo)
        @if($photo->product_id = $product->id)
            <img src="/products/{{ $product->id }}/{{ $photo->filename }}">
        @endif
    @endforeach
@endforeach

But I'd like to have all the photos related to the product in the product collection. I'd like to have a simple view as :

@foreach($products as $product)
    @foreach($product->photos as $photo)
        <img src="/products/{{ $product->id }}/{{ $photo->filename }}"
    @endforeach
@endforeach

Or another way simpler than that. I've been trying merge, but I don't think this is the one I need, I don't know. Or maybe the way I do it is the correct one, but I doubt it.

Thanks for reading !

Upvotes: 0

Views: 62

Answers (2)

Emad Ha
Emad Ha

Reputation: 1222

I don't usually like when people ignore the proposed example and tell you that there's a better way to do that... but there is a better way to do that:

for the Products Eloquent add a method called photos

Class Products extends Model{
     ...
     public function photos(){
          return $this->hasMany(Photos::class);
     }
}

for the Photos Eloquent add a method called product

Class Photos extends Model{
    ...
    public function product(){
        return $this->belongsTo(Product::class);
    }
}

now for the photos migration you need to add a column called product_id in case you're using this photos table only for products and not anything else like users.

if you want to be able to assign photos to multiple models like Users can have photos, then you need to consider using Morphs Polymorphic Relationships

when you want to add photos to the product you can then do

Product::find(1)->photos()->create(['filename'=>'....']);

That should add photos row assigned with the product.

Then in your view you can do something like:

@foreach(Products::all() as $_product)
    <div>
    {{$_product->title}
        <div class="product_photos">
           @foreach($_product->photos as $_photo)
               <img .../>
           @endforeach 
        </div>    
    </div>
@endforeach

I'm just showing you the correct way to achieve that instead of comparing photos with id and so on, your way will make it much slower.

Look up Laravel Relationships. That will take a bit of time like few minutes to convert your models to use Relationships but will save you days of coding later.

Upvotes: 1

George Hanson
George Hanson

Reputation: 3030

I'd recommend using eloquent relationships for this. To do this you would want to create a relationship on the product class called photos. This would look something like this:

class Product extends Model
{
    ...
    public function photos()
    {
        return $this->hasMany(ProductPhoto::class);
    }
    ...
}

Once you have done this, you can update your controller as you no longer need to fetch the photos from the model. For performance, you could eager load the photos.

public function index() {
    $products = Product::with('photos')->get();

    return view('/products')->with([
       'products' => $products
    ]);
}

Finally, you can update your view to use the photos relationship instead.

@foreach($products as $product)
    @foreach($product->photos as $photo)
        <img src="/products/{{ $product->id }}/{{ $photo->filename }}"
    @endforeach
@endforeach

I hope that helps.

Upvotes: 1

Related Questions