TL;DR
$model->relationLoaded('myRelation');
Usage
if ($model->relationLoaded('myRelation')) {
// Look! "myRelation" is already loaded.
}
How it works
This Eloquent method checks if the key “myRelation” exists in the relations array of the Eloquent model. If it exists, which means the realtionships has already been loaded, it returns true
, otherwise, it returns false
.
Function signature
/**
* Determine if the given relation is loaded.
*
* @param string $key
* @return bool
*/
public function relationLoaded($key)
{
return array_key_exists($key, $this->relations);
}
How this method benefited me
Briefly, in one of my projects, I had two tables “artisans”, “products” where artisans hasMany
products, and product belongs
to one artisan, as you can see below.
Artisan model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Artisan extends Model
{
//...
/**
* Products that belongs the artisan
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function products()
{
return $this->hasMany(Product::class);
}
//...
}
Product model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
//...
/**
* Product's owner
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function artisan()
{
return $this->belongsTo(Artisan::class);
}
//...
}
Now whenever I want to fetch an artisan with his products I do this:
$artisan = Artisan::with(['products'])->get();
In the project, the Artisan
model has more relationships, but for simplicity purposes, I will only keep products relationship.
Later on, I frequently find my self eager loading only artisan’s active produtcs. I got to accomplish that by passing an array of relationships to the with
method where the array key is a relationship name (in our case products) and the array value is a closure that adds additional constraints to the eager loading query:
$artisan = Artisan::with(['products' => function ($query) {
$query->where('active', 1);
}])->get();
So, I thought it may be a good idea to create activeProducts
relationship in the Artisan
model to make it more simple and clear. So I did.
Artisan model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Artisan extends Model
{
//...
/**
* Products that belongs to the artisan
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function products()
{
return $this->hasMany(Product::class);
}
/**
* "Active" products that belong to the artisan.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function activeProducts()
{
return $this->products()->where('active', 1);
}
//...
}
Now, without the need to pass a closure to products
relationship to fetch artisan’s active products, I can accomplish the same thing with just this:
$artisan = Artisan::with(['activeProducts'])->get();
Until now everything seems to go smoothly, our code is simple and clear! So, where and when relationLoaded
could possibly be of any help for us.
Let me share with you my use case:
In multiple different places of the application, there is a section where I had to show a random product for an Artisan.
$artisan->randomProduct();
Depending on the Controller, sometimes the eager loaded relationship is products and other times it’s activeProducts relationship. So, the necessity of knowing which relationship was loaded has raised.
relationLoaded to the rescue
Artisan model
/**
* Get random product
*
* @return mixed
*/
public function randomProduct()
{
$products = $this->relationLoaded('products') ? 'products' : 'activeProducts';
return $this->{$products}->isNotEmpty() ? $this->{$products}->random() : null;
}