Laravel 5: when persist form data, _token causes mass assignment exception - php

When I try to persist form data, Laravel is throwing a mass assignment exception.
In the view I'm using {!! form::open(...) !!} which I know creates _token as a hidden field.
When the form data is sent to the controller, I'm using
$data = Input::all();
$order = Order::create($data);
$order->save();
Should I be adding a field for _token in my database? Or am I causing an error by doing something else wrong?

A mass assignment exception is usually caused because you didn't specify the fillable (or guarded the opposite) attributes in your model. Do this:
class Order extends Eloquent {
protected $fillable = ['field1', 'foo', 'bar'];
}
This way you also don't have to worry about _token because only the specified fields will be filled and saved in the db no matter what other stuff you pass to the model.

or
protected $guarded = array();

Make sure you are putting the $fillable or $guarded in the app\Order.php file and not the app\Http\Controllers\OrderController.php file.

To answer your initial question. You would want to do unset($request['_token']); before your create.

Related

Laravel fill not setting component property

I have run into an issue with Laravel that hopefully someone could help explain. The fill command is not setting the properties of the model, and instead can only be used to save them to the database with the ->save() function. Is there a way to do fill where it actually sets the properties of the model from an array.
Example of problem below.
$comment = new comment();
$comment->fill(['name' => 'Bob']);
echo($comment->name); // Gives null/error.
$comment = new comment();
$comment->name = 'Bob';
echo($comment->name); // Gives Bob.
The reason is name filed is not fillable in comment model .To Solve this issue you have to add fillable for that field in comment model
protected $fillable = [
'name',
];
If you try to access non fillable field then it will return null.
If don't want to add it in fillable then you can use forceFill.
forceFill: Fill the model with an array of attributes with force mass assignment.
$comment = new comment();
$comment->forceFill(['name' => 'Bob']);
echo($comment->name);
Yes, you need to use fillable property of the model and need to add name inside fillable array. That's the recommended way to do it.
As suggested by John Lobo's answer, You can forcibly override that mechanism using forceFill or forceCreate.
Both ignores fillable property in the model. It may possible that you may have a column like is_admin and you do not want to update it but force will do it.
Notes :
The main problem with forceCreate or forceFill, is that we have to manage the foreign key assignment manually.
forceFill will do fill (properties) only. You need save method call to save the actual record while forceCreate will do fill (properties) and Save both together.

How to add value of guarded fields in database

I am using laravel 5.3 and in my custom model, I have some guarded fields like following.
protected $guarded = ['id', 'tnant_id', 'org_id', 'fac_id', 'slug', 'created_at', 'updated_at', 'deleted_at'];
Now When I try to add record using following.
CUSTOM::create(['tnant_id'=>123]);
It returns me following error.
Field 'tnant_id' doesn't have a default value.
Setting field default value in table will not work because each time I am passing value and it is giving error for all guarded fields.
So how I can add guarded fields value in database? In update query, It is allowing to update but on create it gives error.
You simply can't. Model::create(array $attributes = []) is using method fill(array $attributes = []), which, we may say, filter out all guarded attributes, so they will not be assigned. So in point of creation tnant_id will be null.
I come up with two ways of doing this:
A
create a new model instance
set your attribute
save (persist) it to dabase;
So:
$model = new Model;
$model->tnant_id = 123;
$model->save();
B
This is more likely update than create, but, might be useful for you.
Change your DB schema to allow null values for your attribute or put default value.
create model using Model::create()
set attribute & update.
So:
Assuming you are using migrations, in your migration file use:
Schema::create(..
$table->integer('trant_id')->nullable();
//OR
$table->integer('trant_id')->default(0);
...);
Note: It's hard to say which one is more suitable for you use-case, but I see your attribute is called trant_id, which is some form of relation I guess, so I suggest you to take look at Eloquent's relationship, which might be a better answer.

Mass assignment, User vs admin, updating a record the right way?

I have removed an element from the mass assignment array.
protected $guarded = ['id', 'status', 'org', 'params', 'last_visited_date'];
Because admin users need to be able to update the user model/record.
However now a user could pass through the element in a form and overwrite a field, this is undesirable.
What's the best way to tackle mass assignment on the mentioned user model?
Hopefully i dont have to have 2 user models?
Looks like i can just manually input
$input = $request->all();
$user->activation = $input['activation'];
$user->save();

Laravel/Eloquent: Validation from within the model

Just getting to grips with Laravel 4.2 and eloquent. I've been watching the Laravel from Scratch casts on laracasts.com, particularly the lessons on validation and the follow up refactoring. The examples used throughout those lessons deal with a relatively basic user model whereby there are only 2 fields, username and password. My user model contains many more fields and my registration form asks for the user to re-enter/confirm the password they have entered.
It seems to be recommended that the process of validating user input should be done within the model, which makes total sense. So just like that tutorial I have gone ahead and added an isValid method to my model to validate user input on my registration form. I fill my user model based on the input like this:
$input = Input::all();
if (!$this->user->fill($input)->isValid()) {
return Redirect::back()->withInput()->withErrors($this->user->errors);
}
So I've written my rules and got the validation working and I am now ready to save the user's input to the database. However, since I've filled my model with the entire user input, the user model instance now contains an attribute of confirm_password and calling $user->save(); gives me an error (Since I don't have this field in my database table). In addition, since I have just passed in the user input to validate, the password there is not hashed either.
What would be the best approach to take with regards to validating user input VS having the model actually represent the database table? I know there are ways I could get around all this by doing things like moving the validation outside the model and perhaps just let the model store the validations rules etc. but I can looking for advice on the best practice.
Thanks
You may remove it before saving, for example:
$input = Input::all();
if (!$this->user->fill($input)->isValid()) {
return Redirect::back()->withInput()->withErrors($this->user->errors);
}
else {
unset($this->user->attributes['confirm_password']);
$this->user->save();
}
This may work but not the proper way for doing it. You may also use a saving event like:
// Goes in to your model
protected static function boot()
{
parent::boot();
static::saving(function($model) {
unset($model->attributes['confirm_password']);
});
}
Since you are validationg inside your model then you may trigger the validation on saving event, like:
protected static function boot()
{
parent::boot();
static::saving(function($model) {
if($model->isValid()) {
unset($model->attributes['confirm_password']);
return true;
}
return false;
});
}
There are nicer ways to accomplish this same thing.
Restrict your Input values. You can pass Input::all() to your validator and still do this.
$input = Input::only('username', 'password');
// – OR –
$input = Input::except('confirm_password');
Add $fillable to your User model.
class User extends Eloquent {
protected $fillable = array('id', 'name', 'email', 'password');
}
Then you can populate the database from the Input and only the columns in the fillable array will be populated. Make sure you have good validation rules if you try this.
$user = User::create(Input::all());
This will accomplish what you are trying to do without unsetting Input values or adding Model events.

laravel mongodb does not save

The documentation doesn't go into much detail about saving data to mongodb.
I've installed a fresh install of laravel and set the up the mongo connections as in the docs, installed mongodb itself.
Created a model
use Jenssegers\Mongodb\Model as Eloquent;
class Notifications extends Eloquent {
protected $connection = 'mongodb';
protected $collection = 'notifications';
public static function foo()
{
return 'test returning from model';
}
}
And create a simple route to test
Route::get('notifiction' , function(){
$notifiction = new Notifications();
$arr = array('name' => 'John Doe');
$notifiction->save($arr);
});
But when I run localhost/mongo/public/notifiction I get Whoops, looks like something went wrong. I'm not sure what else needs doing to save information to mongodb through laravel?
This error is most likely to do with mass assignment. That is laravel treats every thing as unsafe before saving it to database. Thus we have to whitelist the fields we are trying to save.
The way we do this is in model. Lets say you are trying to save data in Users table using USER model. First open app/models/user.php and add following line:
class User extends Eloquent {
protected $fillable = ['name'];
}
Above, in fillable we are listing name as we want to save name from controller (if you have any additional data fill in the array). Now we can save data from controller.
Eg: User::create(array('name' => 'John')); will save name in Users collection. Please note the name of collection will be the name of the model unless specified otherwise.
[If this does not solve your problem, enable debug by going to app/config/app.php and setting debug =true. Find the error and try searching.]
You need not to do like model for SQL.
You try model like this
class User extends Moloquent {
protected $connection = 'mongodb';
protected $collection = 'collection1';
protected $fillable = ['_id','userName','passwd'];
}
You can try this to insert
DB::connection('mongodb')->collection('collection1')
->insert(array(
'_id' => 'H12345',
'userName' => 'Nithil',
'passwd' => 'qwoeuig'));
Using Moloquent is more convenient in using multiple DBS. For using Moloquent, you may register an alias for the MongoDB model by adding the following to the alias array in app/config/app.php:
'Moloquent' => 'Jenssegers\Mongodb\Model',
This will allow you to use the registered alias like:
class MyModel extends Moloquent {}
As OP has mentioned the error was due to
Did not installed the MongoDB PHP Library
Apart from that, to do mass assignment in Laravel, the fields should either be "white listed" or "black listed"
To whitelist the field(s) add
// name, age, username and email could be mass assigned
protected $fillable = ['name', 'age', 'username', 'email'];
To blacklist the field(s) add
// except _id everything could be mass assigned
protected $guarded = ['_id'];
to your model file

Categories