11

In Laravel 5.4 when I try to save User model to the database the values are not saved. I've set the fillable property as well.

It was working in Laravel 5.3. This issue is coming after upgrading the application into Laravel 5.4.

Below is a User model.

class User extends BaseModel implements AuthenticatableContract, CanResetPasswordContract, JWTSubject
{
    use SoftDeletes,
        UserAccess,
        UserAttribute,
        UserRelationship,
        Authenticatable,
        CanResetPassword,
        Notifiable;

    /**
     * Database Table
     *
     * @var string
     */
    protected $table = "users";

    /**
     * The attributes that are not mass assignable.
     *
     * @var array
     */
    protected $guarded = ['id'];

    /**
     * Fillable Form Fields
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'first_name',
        'last_name',
        'email',
        'password',
        'status',
        'confirmed',
        'api_user',
        'confirmation_code',
        'account_id',
        'role_id',
        'cw_contact_id',
        'all',
        'all_locations',
        'username',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = ['password', 'remember_token'];

    /**
     * Select HTML Preference
     *
     * @var string
     */
    protected static $selectHTMLFormat = "[email]";

    /**
     * @var array
     */
    protected $dates = ['deleted_at', 'last_login'];
}

Please note the issue is with User Model only.

I'm saving User as below.

// Create User
        $user = $this->model->create([
            'first_name'        => $input['first_name'],
            'last_name'         => $input['last_name'],
            'username'          => $input['username'],
            'email'             => $input['email'],
            'password'          => bcrypt($input['password']),
            'confirmation_code' => md5(uniqid(mt_rand(), true)),
            'confirmed'         => 1,
            'api_user'          => (isset($input['api_user']) ? $input['api_user'] : 0),
            'account_id'        => $input['account_id'],
            'role_id'           => (isset($input['role_id']) ? $input['role_id'] : 0),
            'all'               => (!isset($input['associated-permissions']) || $input['associated-permissions'] == 'all') ? 1 : 0,
            'status'            => (!isset($input['status']) || $input['status'] ? 1 : 0),
            'all_locations'     => $input['all_locations']
        ]);

Then the create method of BaseModel will be called and below is the code of it.

public static function create(array $attributes = Array())
{
    $user = access()->user();

    if($user)
    {
        $attributes['account_id'] = (!isset($attributes['account_id']) ? $user->account->id : $attributes['account_id'] );
    }

    $childClass     = get_called_class();
    $model          = new $childClass;
    $model->runActionLogger(false, 'create');

    return parent::query()->create($attributes);
}
11
  • What is the question? Commented Apr 6, 2017 at 7:56
  • 1
    show us the code how you save Commented Apr 6, 2017 at 7:57
  • Everything looks OK in User model (without traits). You can use try-catch block to catch stack trace error and please share with us the results. Commented Apr 6, 2017 at 8:05
  • @SteD mentioned it in my question. How i save user. Commented Apr 6, 2017 at 8:21
  • 1
    what is $this when you call $user = $this->model->create? Commented Apr 9, 2017 at 15:47

6 Answers 6

7
+25

The reason is most probably the new middleware in Laravel 5.4 called "Request Sanitization Middleware" as explained in https://laravel.com/docs/5.4/releases.

Disable \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, in app/Http/kernel.php and see what you get.

You can also check in /config/database.php and your mysql connection settings: 'strict' => true, if so, set to false.

A good practice is using the model for user input. In this case, instead of $user = $this->model->create(...) populate you model with $user = new \App\User($input) and update your values from there, f.ex. $user->confirmation_code = md5(uniqid(mt_rand(), true)); and $user->password = bcrypt($user->password);

If fields are nullable, indicate as such in your migration file, f.ex. $table->string('all')->nullable();

If done just run $user->save();

Sign up to request clarification or add additional context in comments.

1 Comment

This is not the case. Middleware is not the case. This above code is working for all other models. Just getting issue with user model.
5

From 5.4 the create() function is not more defined in Illuminate\Database\Eloquent\Model:

Is handled as dinamic method call, that is by calling one of these functions (dependig on if it's called statically or not):

public static function __callStatic($method, $parameters)
// or
public function __call($method, $parameters)

In the Illuminate\Database\Eloquent\Model class.

Now I dont have all your code but, IMHO, I will try to change this line in your BaseModel class:

return parent::query()->create($attributes);

to this:

return $model->create($attributes);

or, even better for me, to this:

return (new static)->newQuery()->create($attributes);

3 Comments

When I'll use $model->create() it will call that model baseModel function only but not the Laravel illuminate. The other alternative is not working for user Model.
try the last one please
Tried but not getting success. I guess it is case of CanResetPasswordContract. If I'm not implementing it the above code will work.
2

In the documentation it says:

$post = App\Post::find(1);

$comment = $post->comments()->create([
    'message' => 'A new comment.',
]);

So

$user = $this->users()->create([
            'first_name'        => $input['first_name'],
            'last_name'         => $input['last_name'],
            'username'          => $input['username'],
            'email'             => $input['email'],
            'password'          => bcrypt($input['password']),
            'confirmation_code' => md5(uniqid(mt_rand(), true)),
            'confirmed'         => 1,
            'api_user'          => (isset($input['api_user']) ? $input['api_user'] : 0),
            'account_id'        => $input['account_id'],
            'role_id'           => (isset($input['role_id']) ? $input['role_id'] : 0),
            'all'               => (!isset($input['associated-permissions']) || $input['associated-permissions'] == 'all') ? 1 : 0,
            'status'            => (!isset($input['status']) || $input['status'] ? 1 : 0),
            'all_locations'     => $input['all_locations']
        ]);

where users() is your public function but I don't know what is $this in your case but should be the model as in the example from documentation.

Why you're not using resource controllers? Or if you need to populate the db use a seeder I think It will be more easy to manage.

2 Comments

I don't want to do like this. As I'm logging each activity so I need to bypass it baseModel only. And it is working with other models but the issue is with User model only.
@ViralSolani can you post more code, just to understand what is $this?
1

So 2 things i can think off

1st there is no need to use

protected $guarded = [];

and

protected $fillable = [];

Guarded will assume everything is fillable if its not in here and fillable will assume everything is guarded unless in here.

To quote the docs

While $fillable serves as a "white list" of attributes that should be mass assignable, you may also choose to use $guarded. The $guarded property should contain an array of attributes that you do not want to be mass assignable. All other attributes not in the array will be mass assignable. So, $guarded functions like a "black list". Of course, you should use either $fillable or $guarded - not both.

2nd to rule out any of the $this->model stuff try instantiate the class first and save them

use App\Path\To\Model as user;

$user = new user();
$user->first_name    = $input['first_name'];
$user->last_name     = $input['last_name'];
$user->username      = $input['username'];
$user->email         = $input['email'];
$user->password      = bcrypt($input['password']);
$user->confirmation_code = md5(uniqid(mt_rand(); true));
$user->confirmed     = 1;
$user->api_user      = (isset($input['api_user']) ? $input['api_user'] : 0);
$user->account_id    = $input['account_id'];
$user->role_id       = (isset($input['role_id']) ? $input['role_id'] : 0);
$user->all           = (!isset($input['associated-permissions']) || $input['associated-permissions'] == 'all') ? 1 : 0;
$user->status        = (!isset($input['status']) || $input['status'] ? 1 : 0);
$user->all_locations = $input['all_locations'];
$user->save();

1 Comment

I don't want to do like this. As I'm logging each activity so I need to bypass it baseModel only. And it is working with other models but the issue is with User model only.
1

Guys I'm able to resolve issue by using Fill() method.

public static function create(array $attributes = Array())
{
    $user = access()->user();

    if($user)
    {
        $attributes['account_id'] = (!isset($attributes['account_id']) ? $user->account->id : $attributes['account_id'] );
    }

    $childClass     = get_called_class();
    $model          = new $childClass;

    $model->fill($attributes);
    $model->save();

    $model->runActionLogger($model, 'create');

    return $model;
}

Also By mistake I've added Construction on CanResetPassword Trait which causing issue as well. So If i remove that everything will work as before as well.

Comments

1

Yes, you can't use __construct method in Traits.

Please Refer PHP.net for more details about trait, they said "Using AS on a __construct method (and maybe other magic methods) is really, really bad."

You can use trait like following way.

class User extends BaseModel
{
    use userRelation
}

Trait userRelation
{
       public function getUserName()
       {
             return "Jhon Doe";
       }
}

I have created "userRelation" Trait which contains few useful code to re-use.

Please refer following link for more details - http://php.net/manual/en/language.oop5.traits.php

Please try it and let me know if it won't work. Thanks

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.