Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Has one through Laravel Eloquent

I have three tables garages, cars, securities.

The securities are the ones that is keeping one car safe, you can have more than one security, but a single security can keep only one car safe. The garage is where the car is and the securities are as well.

What I want is to list all the securities and know the name of the garage that he is. The problem is that securities doesn't have a column containing the id of the garage, only the id of the car that he is keeping safe, but car has the id of the garage.

Laravel Eloquent has a method called hasManyThrough, but securities has one garage through cars only.

Here is the tables:

garages table:

----------------------------------- |garage_id|garage_name|garage_size| ----------------------------------- |        1|   Garage 1|        200| ----------------------------------- |        2|   Garage 2|        400| ----------------------------------- 

cars table:

--------------------------- |car_id|car_name|garage_id| --------------------------- |     1|   Car 1|        1| --------------------------- |     2|   Car 2|        1| --------------------------- |     3|   Car 3|        2| --------------------------- 

securities table:

---------------------------------- |security_id|security_name|car_id| ---------------------------------- |          1|  Security 1|      1| ---------------------------------- |          2|  Security 2|      1| ---------------------------------- |          3|  Security 3|      2| ---------------------------------- |          4|  Security 4|      3| ---------------------------------- 

The output must to be:

Security 1 is on Garage 1 Security 2 is on Garage 1 Security 3 is on Garage 1 Security 4 is on Garage 2 

And I have the models:

The code is to list the garages, but I want to make similar but to list the securities (just for you to have an idea of how the structure is).

$garages = Garages::with(['cars', 'securities'])->get();  $garages->transform(function($garages) {     return array(         'garage_name'      => $garage->garage_name,         'count_cars'       => $garage->cars->count(),         'count_securities' => $garage->securities->count(),    ); });  class Garages extends Eloquent {     public function cars()     {         return $this->hasMany('cars');     }      public function securities()     {         return $this->hasMany('securities');     } }  class Cars extends Eloquent { }  class Securities extends Eloquent { } 

And just to make an emphasis again: I want to have the name of the garage related to the car that the security is keeping safe.

Just to make it even easier to understand, if I do this:

$securities = Securities::with(['cars'])->get();  class Securities extends Eloquent {     public function cars()     {         return $this->hasOne('cars');     } } 

I will get only the garage_id from cars table as relations. What I really want is the name of the garage.

[relations:protected] => Array     (         [cars] => Cars Object             (                 ...                 [attributes:protected] => Array                     (                         ...                         [car_name] => Car 1                         [garage_id] => 1                         ... 
like image 391
yayuj Avatar asked Dec 14 '14 05:12

yayuj


People also ask

Does Laravel 8 have one relation?

A one-to-one relationship in Laravel is a fundamental relation. For example, the User model has only one Bank Account, so he has one account number. So we can connect both models, User, and Bank, as a one-to-one relationship with each other.

What is HasOneThrough in Laravel?

Laravel introduces a relationship: “HasOneThrough”. This is new in Laravel Development but, other framework uses this like “Rails”. The “HasOneThrough” relationship links models through a single intermediate relation. For example, if each group will have users and users will have their users history.

Does Laravel have many through relations?

The “has-many-through” relationship provides a convenient shortcut for accessing distant relations via an intermediate relation. The first argument passed to the hasManyThrough function is the name of the final model we wish to access, while the second argument is the name of the intermediate model.


1 Answers

It looks like you are not relating objects correctly. Let's break that down:

If a Garage Has Many Car then a Car Belongs To Garage, Lets proceed with this idea in mind.

  • Garage Has Many Car
  • Car Has Many Security
  • Security Belongs To Car
  • Garage Has Many Security Through Car

In Eloquent you can just go ahead and clap those relations in, it should work given the schema you posted above.

class Garage extends Eloquent {     public function cars()     {         return $this->hasMany('cars');     }      public function securities()     {         return $this->hasManyThrough('Security', 'Car');     } }  class Car extends Eloquent {     public function securities()     {         return $this->hasMany('Security');     }      // ADDED IN SECOND EDIT      public function garage()     {         return $this->belongsTo('Garage');     }        }  class Security extends Eloquent {     public function car()     {         return $this->belongsTo('Car');     } } 

And that should be it.

EDIT: You can access all these relations from any model as long as there is a path you can draw from one model to another using a combination of these relations. Check this out for example:

$security = Security::with('car.garage')->first(); 

will retrieve first Security record and load Car relation on it, then it goes one more step and load all Garage relations on every Car object loaded under Security model.

You can access them using this syntax:

$security->car->garage->id  // Other examples $garage = Garage::with('cars.securities')->first();  foreach($garage->cars as $car) {     foreach($cars->securities as $security)     {         echo "Car {$car->id} has {$security->id} assigned to it";     } } 

Furthermore, notice that the relationship objects are an instance of Collection so you have all the fancy methods such as ->each(), ->count(), ->map() available on them.

like image 121
Gufran Avatar answered Sep 20 '22 23:09

Gufran