ApeWare's avatar

Accessor returning NULL

We have a field in our company DB table coName that needs to be cleaned before it is displayed. An example value would be "Some Company [HQ]". We would like to strip off the bracketed information so we yield "Some Company". I have a helper function stripBrackets() that handles this fine.

I can create an accessor getDisplayNameAttribute(), add it to the $appends array in the model and it works fine.

protected $appends = ['displayName'];

public function getDisplayNameAttribute()
 {
     return stripBrackets($this->coName);
 }

// "{..."displayName":"Some Company",...}"

If I change the accessor to getCoNameAttribute() and update the $appends array I get a null value

protected $appends = ['coName'];

public function getCoNameAttribute()
{
    $this->attributes['coName'] = stripBrackets($this->attributes['coName']);
}

// "{..."coName":null,...}"


//  I also tried:

protected $appends = [];

public function getCoNameAttribute()
{
    return stripBrackets($this->coName);
}

// and:

protected $appends = [];

public function getCoNameAttribute($value)
{
    return stripBrackets($value);
}

Can anyone point me in the right direction? I can create the additional element displayName and call it a day, but I would prefer to simply modify the original coName value as we will never want to display the bracketed information to a user.

0 likes
4 replies
Snapey's avatar

How about;

protected $appends = [];

public function getCoNameAttribute()
{
    return stripBrackets($this->attributes['coName']);
}

Not sure why it would be different to $this->coName but its the way I always do it

ApeWare's avatar

That will work, but only if I reference coName by $company->coName

If I do this in a test route, to grab a specific company:

$company = \App\Models\Company::where('companyID', 674)->first();

 dd($company::find(674)->toJSON());

//  I get  "{..."coName":"Some Company [HQ]"...}"

It seems if I use an accessor for a field, it doesn't actually modify the data if I return it as an array or JSON, only if I reference it from the collection using something like $company->coName. Maybe this is the intended behavior, but I am trying to understand why it won't actually modify the actual value returned as JSON or an array, the way append does.

Snapey's avatar

You haven't mentioned this option: ?

protected $appends = [];

public function getCoNameAttribute()
{
    $this->attributes['coName'] = stripBrackets($this->attributes['coName']);
}

You shouldn't need to append it if you are using the existing attribute?

there might be a problem here in that the attribute would only be 'fixed' if you first access it with the accessor.

ApeWare's avatar

I actually did try that - maybe after I posted the original question - and it returns the data unchanged in the coNameas

// "{..."coName":"Some Company [HQ]"...}"

there might be a problem here in that the attribute would only be 'fixed' if you first access it with the accessor.

That is what I am wondering about. If you use an accessor that matches an existing column name in the collection, it doesn't seem to run the accessor unless you access it directly through the collection (e.g. $company->coName); it does not seem to affect the attributes if returned as JSON or array.

Is there a way to force this behavior within the Laravel framework or is this something I will need to address some other way? I can program around this - potential - limitation by simply appending an accessor getDisplayNameAttribute(), but I wanted to use this as a learning opportunity on how accessors are supposed to work and make sure I wasn't missing something obvious. The docs didn't seem to go into detail on how Accessors are actually implemented (at what time the accessor fires). I suppose my next step is to go into the code base to get a better understanding of under which circumstances this gets fired but if anyone has any additional insights or a better work around than appending another accessor method, I would be very interested.

Thanks for taking the time to reply.

Please or to participate in this conversation.