Sqrcz's avatar
Level 5

Spatie MediaLibrary - Model->with('media')?

Hey šŸ‘‹

I'm trying to implement "spatie/laravel-medialibrary" within my project and I'm struggling to achieve one thing. I want to show list houses with related images.

Let's say I have a Model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class House extends Model implements HasMedia
{
    use InteractsWithMedia;
    use SoftDeletes;

    public function owner(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function media()
    {
        // ??? Is it possible to "attach" media as any other relation?
    }
}

and Controller:

<?php

namespace App\Http\Controllers\Dashboard;

use App\Http\Controllers\Controller;
use App\Models\House;
use Inertia\Inertia;

class HoseController extends Controller
{
    public function show()
    {
        $houses = House::with('owner')->get();

        return Inertia::render('HosePage', [
            'houses' => $houses,
        ]);
    }
}

According to documentation I can get House photos using getMedia method on my model... like:

$house->getMedia('images')->first()->getUrl('thumb');

And here is my question... Is it possible to pull House media like I'm pulling house owners?

I need to send array of houses to my view and I would like to avoid running queries in foreach loop.

0 likes
1 reply
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

To achieve eager loading of media items with the Spatie MediaLibrary package, you can use the load method to load media for each house after retrieving the houses with their owners. Unfortunately, the getMedia method doesn't work directly with Eloquent's with method because it's not a traditional Eloquent relationship. However, you can still optimize your queries by using the load method after fetching the houses.

Here's how you can modify your controller to include media for each house:

namespace App\Http\Controllers\Dashboard;

use App\Http\Controllers\Controller;
use App\Models\House;
use Inertia\Inertia;

class HouseController extends Controller
{
    public function show()
    {
        // First, retrieve houses with their owners
        $houses = House::with('owner')->get();

        // Then, load media for each house
        $houses->load('media');

        // Alternatively, you can map over the collection to include media URLs
        $housesWithMedia = $houses->map(function ($house) {
            $house->media_urls = $house->getMedia('images')->map(function ($media) {
                return $media->getUrl('thumb');
            });
            return $house;
        });

        return Inertia::render('HousePage', [
            'houses' => $housesWithMedia,
        ]);
    }
}

In this solution:

  1. We first retrieve the houses with their owners using with('owner').
  2. We then use the load method to load the media for each house.
  3. We map over the collection to add a media_urls attribute to each house, which contains the URLs of the media items.

This approach avoids running queries in a foreach loop and efficiently loads the necessary data.

1 like

Please or to participate in this conversation.