Search code examples
laravellaravel-5mass-assignment

Laravel 5.2 mass assignment in model is not working with dynamic table name


I am using Laravel 5.2.

I have a model User in which I want to set the table name dynamically and insert the records into it using mass assignment (i.e. create() method). My code is as,

User:

class User extends Authenticatable
{
    use SoftDeletes;
    use Notifiable;

    protected $table = 'users';

    public function __construct() {
        parent::__construct();
        if(\Session::has("organization_id")){
            $org_id = \Session::get("organization_id");
            $t= $org_id.'_users';
            $this->setTable($t);
        }
    }

    protected $fillable = ['auth0_user_id','username', 'email', 'password',
                            'user_type','first_name','middle_name',
                            'last_name','gender','address',
                            'state','city','country',
                            'post_code','phone','photo',
                            'birth_date','status','doctor_title',
                            'created_by','updated_by','isGuest',
                            'email_varify','confirmation_code', 'membership_code'
                            ];

    protected $hidden = ['password', 'remember_token'];

    protected $appends = ['full_name','name_with_title'];

    protected $dates = ['deleted_at'];
}

UserController:

public function register(Request $request){
    $input = $request->all();
    $input['user_type']='patient';
    $input['password'] = \Hash::make($request->password);
    $input['isGuest']= '1';
    $input['status']= 'Incomplete';
    $input['username'] =  str_random(10);
    $input['confirmation_code']= str_random(30);
    $user = User::create($input);
}

The problem is, it is not inserting any values in respective columns that I have set in $input variable.

I have verified if the table name has changed or not using

$user->getTable();

and it seems OK. I am getting the exact table name.

If I use

dd ($user);

Then it results as following:

App\Models\User Object
(
    [table:protected] => 1_users
    [fillable:protected] => Array
        (
            [0] => auth0_user_id
            [1] => username
            [2] => email
            [3] => password
            [4] => user_type
            [5] => first_name
            [6] => middle_name
            [7] => last_name
            [8] => gender
            [9] => address
            [10] => state
            [11] => city
            [12] => country
            [13] => post_code
            [14] => phone
            [15] => photo
            [16] => birth_date
            [17] => status
            [18] => doctor_title
            [19] => created_by
            [20] => updated_by
            [21] => isGuest
            [22] => email_varify
            [23] => confirmation_code
            [24] => membership_code
        )

    [hidden:protected] => Array
        (
            [0] => password
            [1] => remember_token
        )

    [appends:protected] => Array
        (
            [0] => full_name
            [1] => name_with_title
        )

    [dates:protected] => Array
        (
            [0] => deleted_at
        )

    [connection:protected] => 
    [primaryKey:protected] => id
    [keyType:protected] => int
    [perPage:protected] => 15
    [incrementing] => 1
    [timestamps] => 1
    [attributes:protected] => Array
        (
            [updated_at] => 2016-10-27 05:53:17
            [created_at] => 2016-10-27 05:53:17
            [id] => 20
        )

    [original:protected] => Array
        (
            [updated_at] => 2016-10-27 05:53:17
            [created_at] => 2016-10-27 05:53:17
            [id] => 20
        )

    [relations:protected] => Array
        (
        )

    [visible:protected] => Array
        (
        )

    [guarded:protected] => Array
        (
            [0] => *
        )

    [dateFormat:protected] => 
    [casts:protected] => Array
        (
        )

    [touches:protected] => Array
        (
        )

    [observables:protected] => Array
        (
        )

    [with:protected] => Array
        (
        )

    [exists] => 1
    [wasRecentlyCreated] => 1
    [forceDeleting:protected] => 
)

Here, you may find the table name has successfully changed but I am not finding any columns in [attributes:protected] or in [original:protected].

Also I have tried like:

$user = new User(); 
$user->create($input); 

But nothing seems working.

If I use,

$user = new User(); 
$user->email = $input['email']; 
$user->save()

Then it seems working fine but for that I have to update my codes in many places.

Any solution for mass assignment?


Solution

  • The point is here, that only non-static calls will have the correct table name, because this setTable method is only called when the contructor is called. Therefore, this will work:

    $user = new User; // constructor is called
    $user->someinfo = 'foo';
    $user->save();
    

    And this will not:

    User::create(['someinfo' => 'foo']); 
    // constructor is not called here
    

    So the question becomes then: where to define this conditional table name? You could use something like an event binding, when creating objects, or you could just override the getTable() function with the function provided in your constructor:

    // in your model
    public function getTable() {
      if(\Session::has("organization_id")){
        $org_id = \Session::get("organization_id");
        return $orig_id . '_users';
      }
      return 'users';
    }
    

    A nice solution for this can also be using a trait, which does this action when its booted.

    Good luck! Let me know if this works.

    Update

    I'm sorry, I was wrong. The static create() method does in fact construct the Model:

    public static function create(array $attributes = [])
    {
        $model = new static($attributes);
        $model->save();
        return $model;
    }
    

    I think the point of your original fix was not working, are these lines:

    public function __construct() {
      parent::__construct();
    

    According to the code of create(), you should pass through the $attributes variable also:

    public function __construct(array $attributes = []) {
      parent::__construct($attributes);
      // here your original setTable() code