I know that data can be inserted into the database in
Method 1:
public function store(Request $request)
{
// Validate the request...
$flight = new Flight;
$flight->name = $request->name;
$flight->save();
}
Method 2:
$flight = Flight::create([
'name' => 'London to Paris',
]);
What is the best way to use when inserting 1 value? What is the best way to use when you need to insert, say, 10 values? And are there any other better ways to insert values?
Technically speaking, there isn't much difference, but the main thing about create is that it has mass assignment related issues.
What it means is that, for example if you have a model User which has certain fields including a role field which can be user or admin.
Then if you create a new record using create method like this:
$user = User::create($request->all());
then the member can pass the parameter role in request inputs and change his/her own role and get admin privileges, simple as that! You can prevent this with the property $fillable inside your models, but if it is not taken care of properly it will lead to these kind of issues.
One another point is that, the create method uses the save() itself, if you look at its implementation you can see this:
public function create(array $attributes = [])
{
return tap($this->newModelInstance($attributes), function ($instance) {
$instance->save();
});
}
Related
I have been trying to insert data using query into two columns of a table but there's something missing that its not sending data in the other column named booking_code.
It is inserting the booking_id into the table but not booking_code.
Here is the controller:
public function store(CreatePaymentRequest $request)
{
$input = $request->all();
$booking_id = $request->booking_id;
$booking_code = Booking::find($booking_id)->booking_code;
$this['booking_code'] = $booking_code;
$payment = $this->paymentRepository->create($input);
Flash::success('Payment saved successfully.');
return redirect(route('admin.payments.index'));
}
Please have a look at the Relevant Documentation Pages
You may also use the create method to save a new model in a single line. The inserted model instance will be returned to you from the method. However, before doing so, you will need to specify either a fillable or guarded attribute on the model, as all Eloquent models protect against mass-assignment by default.
That means that you have to set, in Model, which fields you will allow to be "mass-assigned".
In your case, it will looks something like
class Booking extends Model
(...)
{
protected $fillable = ['booking_code', (...)];
}
(...)
In the code you provided though, I can't see how you build an $input variable so maybe the issue is there? Maybe it's just some typo.
I am just learning laravel now. And I have this problem. I have passed 2 request parameters to my controller function. First request parameter holds an object value, but I converted it to a serialized form since the field of my table where it will be saved has a text datatype. The second request parameter holds a overall_total calculated value and it has a float datatype field. My problem is, how would I store it in my database? I have tried to use the create function but it returns an error. Some forums regarding this are not so clear. I just can't figure it out yet. Can somebody help me with this? Here are my codes.
function store
public function store(Request $request){
$serialize_po = serialize($request['purchase_orders']);
$overall_total = $request['overall_total'];
$purchase_orders_save = PurchaseOrder::create(?);
}
How would I save 2 parameters using create? or is there other way I can saved it?
Inside of $request['purchase_orders'] is shown in the image below
Inside of $request['overall_total'] is just a number. E.g. 310
My Database Table Structure is shown below
The create() function in Laravel accepts an associative array, where the array keys are the names of the columns, and the array values are the corresponding values for the columns.
So your store function might look something like this:
public function store(Request $request){
$serialize_po = serialize($request['purchase_orders']);
$overall_total = $request['overall_total'];
$purchase_orders_save = PurchaseOrder::create([
'purchase_orders' => $serialize_po,
'overall_total' => $overall_total
]);
}
One other thing to note is that as a safety precaution, Laravel does not allow the properties of a model to be filled in this fashion out of the box. You will need to list in your model using the $fillable property which keys you will allow to be filled by passing in an associative array. If you don't, you'll likely get a MassAssignmentException.
So in your model, you will likely need to have at least the following:
class PurchaseOrder extends Model
{
protected $fillable = ['purchase_orders', 'overall_total'];
}
There are more options and ways to do this, but that is the basic and typical scenario.
More info on using the create() method and handling mass assignment is available in the documentation: https://laravel.com/docs/5.2/eloquent#mass-assignment
Considering your model name is PurchaseOrder, you first need to create a new instance of it. Then, use the save method.
public function store(Request $request)
{
$purchaseOrder = new PurchaseOrder;
$purchaseOrder->overall_total = $request['overall_total'];
$purchaseOrder->purchase_orders = serialize($request['purchase_orders']);
$purchaseOrder->save();
}
See https://laravel.com/docs/5.2/eloquent#basic-inserts for more info.
Something like this :
DB::table('purchaseOrder')->insert(
['purchase_orders' => $serialize_po,'overall_total' => $overall_total]
);
See doc if you want to explore more.
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.
As there is firstOrCreate()
in Laravel Eloquent, I was wondering if there was a function that could either create a record or if it exists, update the current one?
Or would I have to write my own one?
I wasn't able to find anything in the documentation, but it's not the first time, I've found stuff about Eloquent elsewhere than the docs.
You nearly named it. :)
$instance = Model::updateOrCreate(['id' => $id], $newAttributes);
If $id is null then a new instance will be created and saved, else it will be updated.
You need to find model before updating it, right? You cannot just call Model::firstOrUpdate($newAttributes) simply because there is no model in database with such (new) attributes.
I. e. you must know some model's unique attribute, for example, an id. After this, you can fetch it and call update method with new attributes: Model::firstOrNew(['id' => $id])->update($newAttributes). $id here can be null, in this case new model will be instantiated (but not saved).
As you can see, this code is pretty short, but of course, you might put it into method if you wish.
More straight forward and DRY would it be to add the following method to your BaseModel:
public function write($input, $key = 'id')
{
// Instantiate new OR existing object
if (! empty($input[$key]))
$resource = $this->findOrFail($input[$key]);
else
$resource = $this; // Use a clone to prevent overwriting the same object in case of recursion
// Fill object with user input using Mass Assignment
$resource->fill($input);
// Save data to db
if (! $resource->save())
App::abort(500, 'Could not save resource');
return $resource;
}
PROBLEM 1:
When I try to save() any Yii Model, it updates all fields in the row.
The problem is: When I try to save model users, even if has no PASSWORD to update, it get the database value(already hashed) and hash again.
How can I do to YII only update fields that I want?
Code:
$user = Users::model()->findByAttributes(array('username'=>$this->username));
$user->ip = $_SERVER['REMOTE_ADDR'];
$user->save();
Users.php (Model):
public function beforeSave() {
if (!empty($this->password))
$this->password=$this->hashPassword($this->password);
return true;
}
PROBLEM 2:
I have an API that can create USERS.
API Tutorial: http://www.yiiframework.com/wiki/175/how-to-create-a-rest-api/
When I have crypter_password in the database, instead password, I got the error: Parameter password is not allowed for model Users, because the API validate parameters using $model->hasAttribute().
How can I fix the API actionCreate to allow custom parameters?
According to Yii's doc: http://www.yiiframework.com/doc/api/1.1/CActiveRecord#save-detail
public boolean save(boolean $runValidation=true, array $attributes=NULL)
$attributes - array - list of attributes that need to be saved. Defaults to null, meaning all attributes that are loaded from DB will be saved.
You can pass in an array of fields that you want to save.
Eventhough the other answers listed here are not wrong, they are definitely not really developer friendly and it's extremely easy to forget to add the attributes to the save line.
Here is a developer friendly way of working.
In your model, add the following attribute:
private $_aAttributesBackup;
In this variable, we will store an exact copy of the current model. To do this, the following afterFind method needs to be added:
public function afterFind()
{
$this->_aAttributesBackup = $this->attributes;
}
Almost there. At this point, the model will store all of his attributes in the attributesBackup field which makes it easier to compare. To make it easier, we also need a method that will check if the specified attribute has a backup value. We do this by adding the following code into our model:
public function getOriginalAttribute($sAttribute)
{
if ($this->_aAttributesBackup)
{
return $this->_aAttributesBackup[$sAttribute];
}
return NULL;
}
Now, how about checking if the password has been changed? Simple, by adding the following beforeSave code:
public function beforeSave()
{
if ($this->getOriginalAttribute('password') != $this->password)
{
$this->password = sha1($this->password);
}
return parent::beforeSave();
}
Et voila. Now everytime you execute the code $Model->save(); the system will check if the password has been changed, If the password is changed, it will hash it again, if it is not changed, it won't be hashed again.
Save () inserts a row into the database table if its isNewRecord property is true. Otherwise, it will update the corresponding row in the table (usually the case if the record is obtained using one of those 'find' methods.)
What you have to do is update specific field so you can use SaveAttributes and it accepts the array of string values that have been updated for example demo code is as follow
$user = Users::model()->findByAttributes(array('username'=>$this->username));
$user->ip = $_SERVER['REMOTE_ADDR'];
$user->SaveAttributes(array('ip'));