How to use Cascade Soft Delete Trait in laravel 8? - laravel

$inst = Institution::find($institution->id);
$campus = InstitutionCampusId::where('institution_campus_id.institution_id' , $institution->id);
$inst->delete();
$campus->delete();

Cascading deletes are handled at the database-level, so when you set onDelete('cascade') in your migration, that translates to your database deleting any records attached by foreign key.
Soft deletes are handled by the application, so you'd either need to fire an event on the parent model and listen for it on the children or, in your parent model, bind the static::deleted() method in the boot method, and delete the relationships there.
I'm not sure if you could do something like:
public static function boot()
{
parent::boot();
static::deleted(function ($model) {
// Probably lazy load these relationships to avoid lots of queries?
$model->load([ 'relationshipOne', 'relationshipTwo', ]);
$model->relationshipOne()->delete();
$model->relationshipTwo()->delete();
});
}
Or if you'd have to iterate over the related items:
public static function boot()
{
parent::boot();
static::deleted(function ($model) {
$model->relationshipOne->each(function ($item) {
$item->delete();
});
$model->relationshipTwo->each(function ($item) {
$item->delete();
});
});
}

Add trait to your model use SoftDeletes; and on your migration add $table->softDeletes() on the end of the schema creation (this be automatically create deleted_at column)
And for query you can use eloquent methods to get only deleted or without deleted entries, example:
To get only deleted entries: $query->onlyTrashed(),
To get only non deleted entries: $query->withoutTrashed(),
To get all entries (with deleted): $query->withTrashed()
To send entry in trash use: $model->delete(),
For permanently delete entry use: $model->forceDelete()

add this trait in your model
use SoftDeletes;
add this in your migration it will add deleted at field in your table
$table->softDeletes();

Related

laravel relationship one to many

before anything ,Highly appreciated in advance for help . i have two model
user:
public function posts(){
return $this->hasMany('App\Post');}
post:
public function user(){
return $this->belongsTo('App\user');}
my post have column "user_id" so every post have owner "user_id".
here is my question: i want to delete user but nothing happen to related post. right now i can do this ,but my problem is post_id column have id belongs to deleted user. i want to change that to "null" or "0".
You can do this with model events. Something like this on your User model.
public static function boot() {
parent::boot();
static::deleting(function($user) {
$user->posts()->update(['user_id' => null]);
});
}
Also make sure the user_id field is nullable on the migration.
Just make sure that your post_id field is set to nullable in your migration AND in your database.
You can do this with SQL power - add a migration to your table "posts"
...
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('set null');
It will create a foreign key which sets null to related field on deleting user row
You can change the function boot() from User model:
protected static function boot() {
parent::boot();
static::deleting(function($user) {
$user->posts()->delete();
});
}

How do i delete relation model data along with pivot table data in many to many relation?

User has many to many relation with Report. And upon deleting a user, i would like to delete all their's report and data from report_user pivot table.
Here is my delete() method:
public function delete(Request $request)
{
$user=User::where('id',$request->id);
if($user)
{
$user->delete();
return response()->json(['status'=>true]);
}
}
manually i can delete the users report using:
foreach($user->reports as $report)
{
$report->delete();
}
If there is any better way to delete related models data, i would like to know.
You probably want to setup the users table to reference a foreign key in reports. That way you could leverage the ->onDelete('cascade') method when a user is deleted. See the documentation here
You can use detach() method to delete related models like:
$user->reports()->detach();
So your complete code will be like this:
public function delete(Request $request)
{
$user=User::where('id', $request->id);
if($user)
{
$user->delete();
$user->reports()->detach();
return response()->json(['status'=>true]);
}
}
For more info on detach() method:
https://laravel.com/docs/master/eloquent-relationships

How to listed to deleted event properly?

I have records of a Model that I need to delete, however I need to delete their id's also from the pivot table, so I tried to listed to deleted event, but it didn't work
Here is how I add the event:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Criteria extends Model {
protected $table = 'criterias';
public static function boot()
{
parent::boot();
static::deleted(function($criteria)
{
DB::table('criteria_criteria')->where('criteria_id', '=', $criteria->id)->delete();
});
}
}
I am on Laravel 5.1, any idea how to do so?
I think you have not used its relationship. Please create a relationship with your pivot table like this.
public function criteria()
{
return $this->belongsToMany('App\Criteria');
}
This will automatically manage your deletion query on pivot table. It has also one benifit you can use its sync and detach methods to add and remove pivot table records.
For more detail you can read in this tutorial by search keyword pivot.

Laravel 5 model deleting event ignoring attributes when soft deleting

Something I find puzzling in Laravel 5 is how it handles the the deleting event and any changed attributes. Basically a soft delete is just an update of the deleted_at column on the table. I was trying to be clever and also include the user ID of the user making the delete. Problem is the deleting method ignores the changed attributes when passing them to the query builder.
Take this model for example.
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
use SoftDeletes;
protected $table = 'users';
protected $fillable = [
'user_name', 'created_at', 'created_by', 'updated_at', 'updated_by', 'deleted_at'
];
public static function boot() {
parent::boot();
// This works and updates my updated_by column
User::updating(function($user) {
$user->updated_by = 1;
});
// This is being ignored and does not update the updated_by column
User::deleting(function($user) {
$user->updated_by = 1;
});
}
}
I have traced the create, update and delete model methods. In every case my event listeners are being picked up and processed.
In the create and update save method though, there is a difference. Both of these methods call the getDirty() method which looks for changed attributes and passes the array to the query builder. This is why that insert or update event works.
The delete method however does not do this check and therefore does not pass those attributes to the builder. Although if you look at the stack during the entire oprtation, $this->model['attributes'] has my changed updated_at attribute! The builder just never uses it.
So I guess my question without re-writing the source how would you go about injecting an attribute into the delete method when using soft deletes. Like in my model example.
The end goal here is to update the updated_by field while doing a soft delete. I am trying to avoid first doing an update of the table then doing a delete.
Just override the method runSoftDelete inside your model
class User extends Model
{
protected function runSoftDelete()
{
$query = $this->newQuery()->where($this->getKeyName(), $this->getKey());
$this->{$this->getDeletedAtColumn()} = $time = $this->freshTimestamp();
$query->update(array($this->getDeletedAtColumn() => $this->fromDateTime($time), 'updated_by' => 1));
}
}
I think the problem is the updating event calls the save() function after the event, so any changes you do will be included in the save() call.
The delete event probably does not call the same save() function - so your changes are being lost.
Try to force the save yourself and see if that works?
User::deleting(function($user) {
$user->updated_by = 1;
$user->save();
});

Is it possible to perform "future" soft delete in laravel?

I found that the soft-delete in laravel Eloquent ORM is just replacing the null in deleted_at column by a timestamp. When querying a table with soft delete, is it just checking if the deleted_at is null, or it is really comparing the value with current time?
I am asking to see if I am able to do schedule delete by setting a future time on the deleted_at column.
Laravel only checks if deleted_at is not NULL. SoftDeletingScope:
public function apply(Builder $builder)
{
$model = $builder->getModel();
$builder->whereNull($model->getQualifiedDeletedAtColumn());
$this->extend($builder);
}
You can change that by creating your own SoftDeletingScope and SoftDeletingTrait (it's called SoftDeletes in Laravel 5).
trait MySoftDeletingTrait {
use Illuminate\Database\Eloquent\SoftDeletingTrait;
public static function bootSoftDeletingTrait()
{
static::addGlobalScope(new MySoftDeletingScope);
}
}
And
class MySoftDeletingScope extends Illuminate\Database\Eloquent\SoftDeletingScope {
public function apply(Builder $builder)
{
$model = $builder->getModel();
$builder->where($model->getQualifiedDeletedAtColumn(), '<=', Carbon::now());
$this->extend($builder);
}
}
Note that to be able to remove the scope (the remove() method) you would have to override more of the original scope class. At least also isSoftDeleteConstraint, but I'll leave that to you.
Finally you only have to switch out the trait that you use in your models:
use MySoftDeletingTrait;

Resources