Joe
Joe

Reputation: 1354

Eloquent $appends attributes returning null

I am loading some data into an Eloquent model via an appended attribute and the returned model's attribute is always null. I have protected $appends = array('survey_status); defined in my model (named Survey), and have the accessor defined as such:

public function getSurveyStatusAttribute($value){
    return $value;
}

I have tried setting the attribute both as a property and in bracket notation($this->survey_status = ... & $this->attributes['survey_status'] = ..) and also tried using the setAppends() method prior to returning the model, all to no avail.

This was reported on the Laravel forums back at the end of Sept. 2013 and reported as fixed that Oct. (see: https://github.com/laravel/framework/issues/2336 and http://laravel.io/forum/02-26-2014-model-attribute-accessor-not-working-with-object-get-helper-function)

I am on the most current version of Laravel 4 (v4.2.17) which was released in Feb of this year. And from what I read in the docs and elsewhere it seems as though I'm doing everything correctly. Can any see something I'm not doing or confirm this is still an issue?

UPDATE

So I think I figured out 75% of my issue. I didn't realize you could pass an array to $model->load() to make complex queries using where/orWhere/etc. So this basic example works:

$survey = Survey::find(168);
$survey->load(array('surveyStatus' => function ($q){
  $q->where('organization_id', '=', 7485);
}));

return Response::json($survey);

In the response my SurveyStatus model is supplied. My issue now is I am trying to iterate of a collection of Survey models to add a SurveyStatus relation just like the working one above but the attribute isn't there on the response. This is what I'm using to iterate the collection:

$org->surveySets->each(function ($ss) use ($id){
    $fye = $ss->fiscal_year_end;

    $ss->surveys->each(function ($survey) use ($id, $fye){
      $sid = $survey->id;
      $survey->load(array('surveyStatus' => function ($q) use($id, $fye){
        $q->where('organization_id', '=', $id)->where('fiscal_year_end', '=', $fye);
      }));
      $survey->content_groups->each(function ($cg) use ($id, $sid, $fye){
        $cg->content_rows->each(function ($cr) use ($id, $sid, $fye){
          $cr->questions->each(function ($q) use ($id, $sid, $fye){
            // do the same thing as surveyStatus but load surveyData relation into question
          });
        });
      });
    });
  });

Is there some reason the loading doesn't 'stick' when iterating over a collection?

Upvotes: 1

Views: 5087

Answers (2)

Goopil
Goopil

Reputation: 311

Hello if you want to append some extra data related to another model you could do something like this.

protected $appends = [
    'catName'
];

// relation
public function category()
{
    return $this->hasOne(PostCat::class, 'id', 'id_cat');
}

//getters
public function getCatNameAttribute() 
{
    return $this->category()->getEager()->first()->name;
}

If your related model hold many db row considere this

protected $with = [
    'category'
];

protected $appends = [
    'catName'
];

// relation
public function category()
{
    return $this->hasOne(PostCat::class, 'id', 'id_cat');
}

//getters
public function getCatNameAttribute() 
{
    return $this->category->name;
}

best regards

Upvotes: 0

Matthew Brown
Matthew Brown

Reputation: 5116

Correct me if I'm wrong, but appends doesn't get passed a $value because it's not mapped to a table column. I always thought of it as a computed property of sorts.

Given we have fillable columns 'first' and 'last' we might create an appends called 'fullname'.

protected $appends = [
    'fullname'
];

public function getFullnameAttribute() 
{
    return $this->attributes['fullname'] = $this->first . ' ' . $this->last;
}

Essentially what I think your confusing is that appends is extra data that your appending to your model attributes. You are expected to return a value from the accessor. Returning $value will be null because $value doesn't exist, which is why your manually appending it. Try returning 'foo' in your accessor then you'll see what I mean.

Upvotes: 2

Related Questions