Ad

Laravel Appends

- 1 answer

I have 2 tables. 1.users , 2. user_meta

----------------------      ----------------------
|       users          |         user_meta
----------------------     ----------------------
|id | name | password  |   id|user_id|meta_key|meta_value
 5   xxx      xxxx          1  5       height  6

I want output like: {'id':1,'name':'xxx','height':6}

what i did at User Model**(simply append height to the User Model)**

Protected $appends = ['height'];

public function getHeightAttribute($height)
{
    $height= (new UserMeta)->getUserMeta('height',$this->id);
    return $height;
}

But if i have many meta values like: height,age,sex,color,etc... then i don't think it's a good idea to append all meta data to user Model. Is there any Better solution to get response like {'id':1,'name':'xxx','height':6,'age':24,continue...} without appending to user Model ??

Ad

Answer

pretty straightforward, this is your User model will be like.

  1. Define your meta relationship name in this case i will use metadata
  2. Eager load your metadata relationship on every user query
  3. Hide your relationship value on json/array form of the model
  4. set get attribute mutator, IMPORTANT: must be different name with relationship name
  5. append your attributes on meta attributes.

    class User {
        // 2. eager load user metadata on every user query
        protected $with = [ 'metadata' ];
    
        // 3. hide the relationship data from array/json
        protected $hidden = [ 'metadata' ];
    
        // 5. append meta attribute mutator
        protected $append = [ 'meta' ];
    
        // 1. your user meta relationship
        public function metadata() {
            return $this->hasMany(UserMeta::model, 'user_id', 'id');
        }
    
        // 4. `meta` get attribute mutator
        public function getMetaAttribute() {
            return $this->metadata->mapWithKeys(function($meta) {
                return [$meta['meta_key'] => $meta['meta_value']]
            })->all();
        }
    }
    

This will result in:

$user->toJson();

// result
{
  ...
  'email': '[email protected]',
  'meta': {
      'key1': 'value1',
      'key2': 'value2'
   }
   ...
}

This, in my opinion is better reflection for your code, instead of merging directly with original user attributes, since you can set setMetaAttribute to update your metadata relationship.

but if you insist to merge everything with user attributes, you have to override 2 methods, __get($attribute) and/or toArray() method on your user models.

Ad
source: stackoverflow.com
Ad