Now, let's take a look at a few packages related to Eloquent relationships.
Another package I would like to demonstrate is from Jonas Staudenmeir and is called eloquent-has-many-deep for has many with unlimited levels.
In this example, I have such a structure: Country
-> has many -> User
-> has many -> Project
-> has many -> Transaction
. The goal is to calculate each country's SUM of transactions amount
columns.
After installing the package via composer, we must add the Staudenmeir\EloquentHasManyDeep\HasRelationships
trait to the Model. In this example, it is the Country
Model.
use Illuminate\Database\Eloquent\Relations\HasMany;use Staudenmeir\EloquentHasManyDeep\HasRelationships; class Country extends Model{ use HasRelationships; public function users(): HasMany { return $this->hasMany(User::class); }}
Now, we can use the hasManyDeep
relationship to get transactions. This is similar to the has many through relationship but one deeper lever.
use Staudenmeir\EloquentHasManyDeep\HasManyDeep;use Illuminate\Database\Eloquent\Relations\HasMany;use Staudenmeir\EloquentHasManyDeep\HasRelationships; class Country extends Model{ use HasRelationships; public function users(): HasMany { return $this->hasMany(User::class); } public function transactions(): HasManyDeep { return $this->hasManyDeep(Transaction::class, [User::class, Project::class], ['country_id', 'owner_id', 'project_id'] ); }}
In the hasManyDeep()
method, you first define the target Model. Then, as a second parameter in an array, you provide the intermediate Models. As a third parameter in an array, you provide primary keys if they differ from the default values.
To get the result, you can eager load a relationship as you would with any native Laravel relationship.
$countries = Country::with('transactions')->get(); foreach ($countries as $country) { print '<div><strong>' . $country->name . '</strong>: ' . $country->transactions->sum('amount') . '</div>'; print '<hr />';}
In the database, I have added some data to each table.
And in the browser, we have the result:
You can watch a video review of this package on YouTube.
I recommend checking other available relationships in this package by Jonas Staudenmeir and other packages by him.
Another package that helps us with Eloquent is called tighten/parental. The package helps with Single Table Inheritance (STI). It might sound not very easy, but it isn't. It's a relationship to the same table.
For example, you have a users
table and want to have admins but don't want a different table for them. Using this package, you create a Model Admin
, extend the User
model, and add the HasParent
trait. By doing that, when you call the Admin
Model, Laravel will call the users
table instead of the admins
table, which would be by default.
app/Models/User.php:
use Parental\HasChildren; // The "parent" Modelclass User extends Model{ use HasChildren; // ...}
app/Models/Admin.php:
use Parental\HasParent; // The "child" Modelclass Admin extends User{ use HasParent; // ...}
Type is the only column you must add to the users
table.
Schema::table('users', function ($table) { $table->string('type')->nullable();});
Add
type
to the$fillable
array on theUser
Model.
Now, in your Controller or anywhere, you can call the Admin
Model, which will get records from the users
table.
For more, check the official documentation.
The last interesting and handy Eloquent package is about cascading soft deletes. The problem is that if you use soft deletes on parent and child relationships if you soft delete the parent record, the child doesn't get automatically soft-deleted.
That happens because soft deletes are not the function of MySQL or database. It's a function of Laravel and Eloquent.
I have added softDeletes()
to the User
and Task
Models. The User
Model has many tasks. In the database, I have a user and two tasks that belong to that user.
If using Tinker, I delete this user, it gets soft deleted by Laravel, but the tasks don't.
This is where the michaeldyrynda/laravel-cascade-soft-deletes
package comes in help. After installing the package via composer, you must add the CascadeSoftDeletes
Trait and provide children relationships in the $cascadeDeletes
array property.
app/Models/User.php:
use Illuminate\Database\Eloquent\SoftDeletes;use Dyrynda\Database\Support\CascadeSoftDeletes; class User extends Authenticatable{ use HasFactory, Notifiable; use SoftDeletes, CascadeSoftDeletes; // ... protected array $cascadeDeletes = ['tasks']; // ... public function tasks(): HasMany { return $this->hasMany(Task::class); }}
Now, after soft deleting the user, tasks are also soft deleted.
For more, read the official documentation.