GluePear
GluePear

Reputation: 7715

Conditional responses in Laravel Eloquent API resources

Laravel 5.7. I have a model Audio, with the fields id and title. An Audio can have many AudioVersions, where AudioVersion has id, audio_id (referring to Audio) and url.

Now, I have two parent models, Foo and Bar, which can have many Audio models.

Audio:

class Audio extends Model
{
    public function versions()
    {
        return $this->hasMany('App\AudioVersion', 'audio_id');
    }
}

AudioVersion:

class AudioVersion extends Model
{
    public function audio()
    {
        return $this->belongsTo('App\AudioContent');
    }
}

Foo:

class Foo extends Model
{
    public function audioContents()
    {
        return $this->morphToMany('App\Audio', 'audio_contentable', 'audio_contentable');
    }
}

I have an Eloquent API resource, FooResource, which returns its Audio objects:

FooResource:

class FooResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'audio' => AudioResource::collection($this->audioContents),
        ];
    }
}

AudioResource:

class AudioResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'urls' => $this->versions,
        ];
    }
}

My problem is that in the audio key of my FooResource I only want to return Audios which have AudioVersions related to them. I.e. if I have an Audio with no AudioVersions, I do not want that Audio included in the Foo's audio key. I can't find a way to do this deep conditional logic in Eloquent / Resources.

Upvotes: 0

Views: 954

Answers (3)

GluePear
GluePear

Reputation: 7715

In the end I added a scope to Audio:

public function scopeHasVersions($query)
{
    return $query->whereHas('versions');
}

Then in FooResource:

return [
    'audio' => AudioResource::collection($this->audioContents()->hasVersions()->get()),
];

Upvotes: 0

thisiskelvin
thisiskelvin

Reputation: 4202

In the FooResource class, you could filter() the collection before passing it to the collection method.

class FooResource extends JsonResource
{
    public function toArray($request)
    {
        $audioContents = $this->audioContents()->filter(function($audio, $key) {
            return $audio->versions->count();
        }

        return [
            'audio' => AudioResource::collection($audioContents),
        ];
    }
}

Upvotes: 1

Priyanka khullar
Priyanka khullar

Reputation: 517

You need to do something like this. This is the example, you only need to add join inside with so that only those audios will be fetched which have audio versions.

$audioContents = AudioContents::with([
    'audio' => function ($query) use ($SpecificID) {
        return $query->join("audio_versions")
                    ->on("audio_versions.audio_id", "=", "audios.id");
    }
])->get();

Try this and let me know if you are facing any issue.

Upvotes: 0

Related Questions