Laravel force delete event on relations - php

I'm developing a Laravel web app using Laravel 5.2. My question is very simple... How do I listen to a forceDelete event in order to forceDelete model relations?
I've been looking around the web and S.O. for a few but all the questions/answers I've found where releted to the delete method, and also in the API documentation I haven't found very much...
In my case I have a Registry model and a RegistryDetail model
Registry table
|id|name|surname|....
RegistryDetail table
|id|id_registry|....
I've created for both this boot function:
protected static function boot()
{
parent::boot();
static::deleted(function($registry) {
// Delete registry_detail
$registry->registryDetail->delete();
});
static::restored(function($registry) {
// Restore registry_detail
$registry->registrydetail()->withTrashed()->restore();
});
}
Since both models have SoftDeletes the static::deleted function is called only when the delete() method is called. if I call a forceDelete() method the related model won't be deleted from the database.
If you need more informations let me know.
Thanks in advance

The deleted event should still fire when calling forceDelete(). Inside the deleted() event method, you can check the the forceDeleting protected property via isForceDeleting() to see if you're in a regular delete or a forced delete.
static::deleted(function($registry) {
// Delete registry_detail
if ($registry->isForceDeleting()) {
$registry->registryDetail->forceDelete();
} else {
$registry->registryDetail->delete();
}
});

Related

Setting up a kind of BelongsToThrough relationship in Laravel

Here is my current situation:
I have a Task model.
Tasks have owners (a belongsTo relationship)
Owners have accounts (yet another belongsTo relationship)
I'd like to set up a "belongsToThrough" relationship from Tasks to Accounts.
My first solution was to define a relationship in the Tasks model, like this:
public function account(): BelongsTo
{
return $this->owner->account();
}
With it I could call $task->account and retrieve a task's account easily. The problem is that this doesn't work with load/with, which in turn causes problems because I can't refresh() a task that has had the account loaded in (because refresh uses load). The error just states Trying to call account() on null which was honestly expected.
My second solution was to change the relationship method to:
public function account(): BelongsTo
{
return $this->owner()->first()->account();
}
With this, I can also simply call $task->account and retrieve the model, and when loading, it doesn't work (returns null), but also doesn't throw any errors. I don't need to load this relationship in, it just happens that sometimes I need to refresh models and having the load method throw an error is not ok.
In summary
What I'm looking for is kind of a BelongsToThrough, as a Task would BelongTo an Account through an Owner (User). Is there a way to do this that works using both $task->account and $task->load('account'). Before you tell me I can load it using owner.account, I know that, but refresh() will do it automatically with load('account') so I need it to work like that, not with the dot notation.
To get it working with load(), you'll need to define an account relationship on the owner model, if you haven't done so already. Like this:
public function account() :BelongsTo
{
return $this->belongsTo(AccountsTable);
}
Then use dot notation when calling load() on your task model like:
$task->load('owner.account');
You can do that using eager loading
public function account()
{
return $this->belongsTo('App\ParentModel', 'foreignkey', 'localkey');
}
After that you can easily fetch relation data with load/with.
Thanks,

laravel5.2 delete model with all relations

My current model has some relations. How can I delete them too, in case of model will be deleted?
This query won't delete the related models, only the 'main model'.
I use this code to call:
$checks = Check::where('created_at','<=', Carbon::now()
->subHours(3))
->with('checks')
->with('results')
->delete();
Here's my current model of Check
protected static function boot(){
parent::boot();
static::deleting(function($check) {
$check->checks()->delete();
$check->results()->delete();
});
}
Results and checks contain more than one entry for each check. Meaning this to make things clear:
One check may have n CheckResult and may have n CheckProcedure (I'll of course delete all of them too).
Try to use deleted instead of deleting :
protected static function boot(){
parent::boot();
static::deleted(function($check)
{
$check->checks()->delete();
$check->results()->delete();
});
}
Also try to parse object by object from returned collection:
foreach($check->checks as $check_object) {
$check_object->delete();
}
Hope this helps.
Like already pointed out in the comments, you are performing the delete on a query builder instead of the actual related models. i.e.
You should have
$check->checks->delete();
$check->results->delete();
instead of what you currently have.
In addition, the right way to do this assuming you are using a relational database is to use foreign keys with cascade delete action.

Laravel 5.1 Event deleting and delete not fire

I Works with Laravel 5.1 and works with events creating, updating, deleting. creating and updating works fine, but deleting method not fire. I have tests in Model, creating an Observer class and put into EventServiceProvider without any solution.
My code:
public static function boot()
{
parent::boot();
static::deleting(function($user)
{
if(count($user->getImages()) >0){
return false;
}else{
return true;
}
});
}
My code delete:
User::where('id','=',$id)->delete();
Any suggestion? Thank for all in advance
Try to use User::where('id','=',$id)->first()->delete(); It must be work, I have the same bug in my project.
For multiple rows:
User::where('id', $id)->get()->each(function($row){
$row->delete();
});
the next option if you shoot the events deleted, deleting
User::destroy(id);
or
User::destroy([id1, id2, id3]);

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.

Laravel 4 Model relation Event?

Are there any events that fire when a new model relation is created? e.g.
$comment = Comment::create( array('title' => 'hello world!') );
$post->comments()->save($comment);
are there any events that are fired when the comment to post relation is saved? This would be very handy in certain use cases.
As an example in my app i have users and organisations. When i add a user to an organisation:
$user->organisations()->save($organisation);
i would love this to fire an event where i could bind the user to the organisations permission groups.
I think you can register Model Observers.
From the docs:
class UserObserver {
public function saving($model)
{
//
}
public function saved($model)
{
//
}
}
User::observe(new UserObserver);
http://four.laravel.com/docs/eloquent#model-observers
I have never used them, and I am not certain if they are necessary for your scenario, but I think this is the way to go if you really want to do it.

Categories