Question

I am having problems with abstracting a model dependency in Laravel.

I have a Metal model and a Fix model. A Metal has many Fixes, but when I query the Metal model, I need an attribute on the Metal model which is dependent on a specific associated fix.

I do this using an accessor which queries the fix model from within the Metal Model.

Example below:

class Metal extends Eloquent
{
  protected $table = 'metals';

  public function fixes()
  {
    return $this->hasMany('Fix');
  }

  public function getFixAttribute()
  {
    $fix = Fix::where('metal_id', $this->id)
    ->where('currency_id', Session::get('currency'))->remember(10)->first();

    $amFix = $fix->am;

    return $amFix;
  }

  protected $appends = array('fix');
}

Without the ->remember(10), each time the Metal model is required, I will end up performing a db query for every row queried in the metal table. n+1 problem.

example - assuming that there are 10 metals in the database, dd(Metal::all()); will query the metals table, then the fixes table 10 times to get the fix attribute for each metal.

Further, I don't need the fixAttribute every time, but i will need it quite often - which is why I am appending the attribute accessor.

What is the best way of tackling this problem? Can anybody point me into the right direction?

Ideally, I want to query the fixes table once giving me one fix for each metal, then match up the metal_id's with the metals table and use that in the metals fix accessor.

Pas de solution correcte

Autres conseils

I think you can use Eager Loading (Eager Load Constraints) to reduce the n+ query problem using with method:

$metalsWithFixes = Metal::with(array('fixes' => function($q){
    $q->where('currency_id', Session::get('currency'));
}))->get();

Update: You can use the relationship as $metalsWithFixes->first()->fixes and can select fields from fix tablw but the relation key (metal_id) must be present in the select array:

$metalsWithFixes = Metal::with(array('fixes' => function($q){
    $q->where('currency_id', Session::get('currency'))->select(array('metal_id', 'am'));
}))->get();

You can use a loop in your view (blade) as:

@foreach($metalsWithFixes as $metal)

    {{ $metal->fieldName }}

    @foreach($metalWithFix->fixes as $fix)
        {{ $fix->am }}
    @endforeach;

@endforeach

Since, it's a one-to-many relationship so the $metal->fixes will return more than one fix or one (if there is only one) but as an array.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top