I have 3 models: Environments, Sites and Incidents. Each have their respective tables.
My model relationships are defined as follows:
Environments have many Sites ( environment_id
in sites table)
public function sites()
{
return $this->hasMany('App\Site');
}
Sites belong to an Environment ( environment_id
in sites table) and belong to many Incidents (incident_site relationship table with incident_id
and site_id
)
public function environment()
{
return $this->belongsTo('App\Environment');
}
public function incidents()
{
return $this->belongsToMany('App\Incident');
}
Incidents belong to many Sites (incident_site relationship table with incident_id
and site_id
)
public function sites()
{
return $this->belongsToMany('App\Site');
}
Problem: I am trying to retrieve a collection of all Site Incidents through the Environment model like this:
$environment->incidents()->count();
The only way I've been able to get it to work in a controller so far is like this:
$environment->load(['sites.incidents' => function ($q) use ( &$incidents ) {
$incidents = $q->orderBy('id','desc')->get();
}]);
But it's not ideal to work with in other areas of the App.
Question: How do I go about making the above relationship work through a method in the Environment model? Is there an easier way?
There isn't any provision for using hasManyThrough()
in many-to-many relation. But you can achieve this by using either DB::raw()
or you can add following function to your BaseModel as given in this forum .
public function manyThroughMany($related, $through, $firstKey, $secondKey, $pivotKey)
{
$model = new $related;
$table = $model->getTable();
$throughModel = new $through;
$pivot = $throughModel->getTable();
return $model
->join($pivot, $pivot . '.' . $pivotKey, '=', $table . '.' . $secondKey)
->select($table . '.*')
->where($pivot . '.' . $firstKey, '=', $this->id);
}
Update: Use
first you would need to create a Model for incident_site
class incident_site extends Model{
public $table = 'incident_site';
//your other code
}
In your Enviorment
model add the Incidents()
method:
public function Incidents()
{
return $this->manyThroughMany('App\Incident', 'App\incident_site', 'site_id', 'id', 'incident_id');
}
Have modified the function according to your needs.
Change your function to following:
public function manyThroughMany($related, $through ,$middle , $firstKey, $secondKey, $pivotKey)
{
$model = new $related;
$table = $model->getTable();
$throughModel = new $through;
$pivot = $throughModel->getTable();
$middleModel = new $middle;
$middleModelIds = $middleModel->where($this->getForeignKey(),$this->getKey())->get()->lists('id')->toArray();
//$middleModelIds = $this->with($middleModel)->where()->get()->lists('id')->toArray();
//$middleModelIds = $this->sites()->get()->lists('id')->toArray();
return $model
->join($pivot, $pivot . '.' . $pivotKey, '=', $table . '.' . $secondKey)
->select($table . '.*')
->whereIn($pivot . '.' . $firstKey,$middleModelIds);// '=', $this->id);
}
Use:
Extra argument of middle table needs to passed.
public function Incidents()
{
return $this->manyThroughMany('App\Incident', 'App\incident_site','App\Site','site_id', 'id', 'incident_id');
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.