How to incorporate ->isDirty() with laravel ->update() - php

I want to check if certain columns in database are changed.
the update code in my controller goes like this:
$tCustomer = TCustomer::withTrashed()->findOrFail($id);
$tCustomer->update(request()->all());
How do I incorporate it with the ->isDirty() function?
I tried adding it after $tCustomer->update(request()->all()); but it always returns false:
$dirty = $tCustomer->getDirty('payment_method_id');
do I have to add isDirty() before or right after the update?

You can uuse fill() instead of update(), check for isDirty(), then save(). This way you can take advantage of the mass injectable fields.
$myModel->fill($arrayLikeinUpdate);
if ($myModel->isDirty()) {
// do something
}
$myModel->save();

You have to use observers, you can use updating() eloquent model event for before saving the model or updated() after saving model, you just have to add below code in your TCustomer model:
public static function boot(){
static::updated(function($tCustomer){
if($tCustomer->isDirty('field_name')){
//This code will run only after model save and field_name is updated, You can do whatever you want like triggering event etc.
}
}
static::updating(function($tCustomer){
if($tCustomer->isDirty('field_name')){
//This code will run only before saving model and field_name is updating, You can do whatever you want like triggering event etc.
}
}

isDirty returns a bool, so you'd use it with a conditional to check if a given models attributes have changed. Example:
// modify an attribute
$myModel->foo = 'some new value';
....
// do other stuff
...
// before the model has been saved
if ($myModel->isDirty()) {
// update model
$myModel->save();
}
So the check needs to be done before you update (save) the model.
Calling update saves the model with the given attributes in one call so you wouldn't use isDirty in that context.

Related

Laravel replace variable on Model

I would like to be able to override a variable on the model, so that a normal field is instead replaced by a relationship's field, i.e.
Where product.image might normally be a field, I want to run a function which will go through all of the resulting products from a query and replace the image field with something like the following --
(Product.php) Model
...
public function variantImages(){
return $this->image = $this->variants()->first()->pluck('image_url');
}
...
So the default product image field is replaced by the "first product variant's image". I don't want to do this in a collection once I have already got the data, the problem here is being able to do this at a Model level.
Is there a way to do this within a scope?
You can create an accessor instead of a normal function:
// Singular because it only gets one
public function getVariantImageAttribute(){
return $this->image = $this->variants()->first()->pluck('image_url');
}
This will make it available under $product->variant_image
Then you can ensure it is always appended to your model (if you want) by adding it to the appends e.g.:
$appends = [ 'variant_image' ];
Since this is not the best idea since it will force load the relationship every time you get a product (even if you didn't request it) you can conditionally control when to append it via e.g.:
return response()->json($product->append('variant_image'));
Note that the append method also works for collecitions of eloquent models.

Insert data into two columns of a table in Laravel Controller using sql

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.

Tracking database changes on related models... Laravel 5.1

We are trying to detect the changes in Laravel related models at attribute level, as we have to keep audit trail of all the changes which are made via the application.
We can track the changes via isDirty method on the Eloquent model for single model that is not related to any other model, but there is no way that we can track the changes on the related eloquent models. isDirty doesn't work on related models attributes. Can some one please help us on this?
Update to original question:
Actually we are trying to track changes on the pivot table that has extra attributes as well defined on it. IsDirty method doesn't work on those extra attributes which are defined in the pivot table.
Thanks
As much I understand your question, It's can achieve through Model Event and some sort of extra code with current and relation model.
Laravel Model Events
If you dont want to use any additional stuff, you can just use the Laravel Model Events (that in fact Ardent is wrapping in the hooks). Look into the docs http://laravel.com/docs/5.1/eloquent#events
Eloquent models fire several events, allowing you to hook into various
points in the model's lifecycle using the following methods: creating,
created, updating, updated, saving, saved, deleting, deleted,
restoring, restored.
Whenever a new item is saved for the first time, the creating and
created events will fire. If an item is not new and the save method is
called, the updating / updated events will fire. In both cases, the
saving / saved events will fire.
If false is returned from the creating, updating, saving, or deleting
events, the action will be cancelled:
Finally, reffering to your question you can utilize the above approaches in numerous ways but most obviously you can combine it (or not) with the Eloquent Models' getDirty() api docs here method and getRelation() api docs here method
It will work for example with the saving event.
Model::saving(function($model){
foreach($model->getDirty() as $attribute => $value){
$original= $model->getOriginal($attribute);
echo "Changed";
}
$relations = $model->getRelations();
foreach($relations as $relation){
$relation_model = getRelation($relation);
foreach($relation_model->getDirty() as $attribute => $value){
$original= $relation_model->getOriginal($attribute);
echo "Relation Changed";
}
}
return true; //if false the model wont save!
});
Another Thought might help you. when you saving
save() will check if something in the model has changed. If it hasn't it won't run a db query.
Here's the relevant part of code in Illuminate\Database\Eloquent\Model#performUpdate:
protected function performUpdate(Builder $query, array $options = [])
{
$dirty = $this->getDirty();
if (count($dirty) > 0)
{
// runs update query
}
return true;
}
The getDirty() method simply compares the current attributes with a copy saved in original when the model is created. This is done in the syncOriginal() method:
public function __construct(array $attributes = array())
{
$this->bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
public function syncOriginal()
{
$this->original = $this->attributes;
return $this;
}
check model is dirty isDirty():
if($user->isDirty()){
// changes have been made
}
Or check certain attribute:
if($user->isDirty('price')){
// price has changed
}
I did not check this code but hopeful to use as your answer by thoughts, if you have any confusion to deal such requirement or something need to optimize or change please let me know.

Model attributes set in beforeSave() are not being saved

I am trying to set a model attributes in beforeSave() method but they are not saved afterwards.
public function beforeSave(){
if(!$this->isNewRecord){
// ...
$this->status = self::VISIBLE;
}
return parent::beforeSave();
}
I have tried returning true instead of parent::beforeSave().
Also I have tried if(parent::beforeSave) {} structure.
I have checked model attributes in afterSave and they are set. I just don't get there they can get lost afterwards.
Any ideas?
Basically you are updating a model above..
if(!$this->isNewRecord).
Remove this conditin while saving with status field
I just tried to update the model without X-editable plugin and the additional attributes were set in beforeSave().

Yii2 triggering a model/record update from afterSave

After saving a new model / active record in Yii2, I'm scheduling a job on the filesystem. I do this in afterSave and I would like to update the record with the job id of the scheduler I get back.
But when I call $this->update() in the model after setting the correct property to the job id, no update is happening. Using update() in an afterSave() is probably a bad idea, but what would then be the right way to tackle this?
You can use updateAttributes($attributes)
This method is a shortcut to update() when data validation is not
needed and only a small set attributes need to be updated.
You may specify the attributes to be updated as name list or
name-value pairs. If the latter, the corresponding attribute values
will be modified accordingly. The method will then save the specified
attributes into database.
Note that this method will not perform data validation and will not
trigger events.
http://www.yiiframework.com/doc-2.0/yii-db-baseactiverecord.html#updateAttributes()-detail
I see 2 options there:
Create additional internal field in the model, something like private $task_sended = false; In afterUpdate set task_sended = true and check It
if (!$this->task_sended){
//send task to scheduler
$this->task_sended = true;
}
Use DAO command to update model
\Yii::$app->db->createCommand()->update(self::tableName(), $update, ['id'=>$this->id])->execute();

Categories