Search code examples
phplaraveleloquentmass-assignment

Laravel eloquent Mass assignment from multi-dimentional array


I'm creating a Restful application, so I'm recieving a POST request that could seem like this

$_POST = array (
'person' => array (
    'id' => '1',
    'name' => 'John Smith',
    'age' => '45',
    'city' => array (
        'id' => '45',
        'name' => 'London',
        'country' => 'England',
    ),
),

);

I would like to save my person model and set its city_id.

I know that the easiest way is to set it manually with $person->city_id = $request['city']['id]; but this way isn't helping me....this code is only an example, in my real code, my model has 15 relationships

Is there any way to make it in a similar such as $person->fill($request);?

My models look like:

City

class City extends Model {

    public $timestamps = false;
    public $guarded= ['id'];//Used in order to prevent filling from mass assignment

    public function people(){
        return $this->hasMany('App\Models\Person', 'city_id');
    }

}

Person

class Person extends Model {

public $timestamps = false;
public $guarded= ['id'];//Used in order to prevent filling from mass assignment

public function city(){
    return $this->belongsTo('App\Models\City', 'city_id');
}
public static function savePerson($request){//Im sending a Request::all() from parameter
    $person = isset($request['id']) ? self::find($request['id']) : new self();
    $person->fill($request);//This won't work since my $request array is multi dimentional
    $person->save();
    return $person;
}

}


Solution

  • This is a bit tricky, but you can override fill method in your model, and set deeplyNestedAttributes() for storing attributes thats will be looking for in the request

    class Person extends Model {
    
        public $timestamps = false;
        public $guarded= ['id'];//Used in order to prevent filling from mass assignment
    
        public function city(){
            return $this->belongsTo('App\Models\City', 'city_id');
        }
    
        public static function savePerson($request){//Im sending a Request::all() from parameter
            $person = isset($request['id']) ? self::find($request['id']) : new self();
            $person->fill($request);//This won't work since my $request array is multi dimentional
            $person->save();
            return $person;
        }
    
        public function deeplyNestedAttributes()
        {
            return [
                'city_id',
                // another attributes
            ];
        }
    
        public function fill(array $attributes = [])
        {
            $attrs = $attributes;
            $nestedAttrs = $this->deeplyNestedAttributes();
    
            foreach ($nestedAttrs as $attr) {
                list($relationName, $relationAttr) = explode('_', $attr);
    
                if ( array_key_exists($relationName, $attributes) ) {
    
                    if ( array_key_exists($relationAttr, $attributes[$relationName]) ) {
    
                        $attrs[$attr] = $attributes[$relationName][$relationAttr];
                    }
                }
            }
            return parent::fill($attrs);
        }
    
    }