CROSP's avatar

Laravel attribute accessor, capital letter is ignored

I am using Lumen framework. I have one problem, I need to set custom accessor for attribute, but the problem is that column in database starts with capital letter. For example Logo.And in case of first capital letter, accessor is not called while retrieving object, I have tried with several columns, columns with name starts from small letter works perfectly.

public function getLogoAttribute($value) This accessor doesn't work ,because name of column is Logo I cannot change the name of columns in the database, but need to use accessors in my application. I understand that I can change sources of Eloquent framework, but maybe there any other way to get it working. Thanks.

0 likes
8 replies
jekinney's avatar

Create your own method or manipulate the data after to perform a query.

Laravel does a lot, but using php when Laravel helpers can't be used is priceless.

1 like
Snapey's avatar

something like

public function getLogoAttribute()
{
    return $this->Logo;
}
1 like
CROSP's avatar

@jekinney , do you mean just to do required actions for example after NewsArticles::all() in retrieved data ?

The problem that I don't understand why it doesn't work, I have found method which determines if get mutator exists.

    /**
     * Determine if a get mutator exists for an attribute.
     *
     * @param  string  $key
     * @return bool
     */
    public function hasGetMutator($key)
    {
        return method_exists($this, 'get'.Str::studly($key).'Attribute');
    }

But it seems that Logo is not passed to this method at all so I guess such fields were filtered somewhere before calling this method

I have found the problem, accessor works as it should, but it is not called in json response (only for fields starting with capital letter).

 return NewsArticle::find($id)->Logo

This works like expected.

Please help to find the problem or at least maybe someone knows where this conditional check is in source code of lumen (eloquent) ?

thomaskim's avatar

Do you have Logo listed in your hidden attributes?

CROSP's avatar

@thomaskim , No.

I have found the evil method)

   public static function cacheMutatedAttributes($class)
    {
        .........
              if (static::$snakeAttributes) {
                    $matches[1] = Str::snake($matches[1]);
                }
                $mutatedAttributes[] = lcfirst($matches[1]);

}

The problem is here, that it returns the array of mutated attributes (cache), but I don't know where this cache is used except this Model class.
I guess somewhere in response class , but I have tried to find grepping all files, occurrences were found only in Model class.

Please help to find the method, I am new to Laravel Internals)

1 like
CROSP's avatar

Found the evil method

public function attributesToArray()
    {
        $attributes = $this->getArrayableAttributes();
$mutatedAttributes = $this->getMutatedAttributes();

        // We want to spin through all the mutated attributes for this model and call
        // the mutator for the attribute. We cache off every mutated attributes so
        // we don't have to constantly check on attributes that actually change.
        foreach ($mutatedAttributes as $key) {
            if (! array_key_exists($key, $attributes) ) {
                if(array_key_exists(ucfirst($key), $attributes)) {
                    $key = ucfirst($key);
                }
                else {
                    continue;
                }
            }
} 

This is modified version of this method. As you can I added check if attribute doesn't exist perform another check with upper first letter.
Note this will only work with one first capital letter, if name consist of multiple capital letters another check should be used.

1 like
zwendi's avatar

@CROSP you are totally right. I guess here eloquent takes too much assumption for the naming convention users gonna use for existing databases. For sure if for people stick to all those conventions from the beginning it is a great thing but it is tough to use the framework for existing databases.

Snapey's avatar

@zwendi There is nothing stopping you from using the lower case version. The attributes of the model don't have to be exactly the same as the table columns?

If I have a column Fred and an accessor getFredAttribute then I can just use $model->fred instead whenever I need to use the accessor/mutator

Please or to participate in this conversation.