Laravel: Soft Delete an item - php

I would like to delete an item only on my page "overview" however I will wish to keep the element on my database. Is it possible ?
Do you have an idea of the procedure ?
I don't know how to do softdelete, in my Controller I have that
public function destroy(Devis $devis)
{
$devis->delete();
return redirect('/admin');
}
In my route I have that
Route::group(['middleware' => ['auth']], function () {
Route::get('/admin', 'AdminController#getHome');
Route::get('/valider/{devis}', 'AdminController#destroy');
});
In my file overview I have that
#foreach($devis as $item)
<tr>
<td> {{$item->firstname}}</td>
<td> {{$item->lastname}} </td>
<td> {{$item->phone}} </td>
<td> {{$item->start_adress}} -- {{$item->start_floor}}</td>
<td> {{$item->end_adress}} -- {{$item->end_floor}}</td>
<td> {{$item->type_intervention}}</td>
<td> {{$item->email}} </td>
<td> {{$item->remarks}} </td>
<td> <span class="left ion-close"></span></td>
</tr>
#endforeach

Using Soft Deletion you mark an item in a way that it's no longer displayed
within the application.
Laravel natively support soft deletion, you just have to enable it on the
specific model where you need it.
In Laravel 5 or later, if you have for example the model Book, in order to enable it you need to:
1. Create a new migration
$ php artisan make:migration add_soft_delete_to_books --table=books
2. Modify the migration adding the "deleted_at" column. The Laravel schema builder contains a helper method softDeletes() to create this column.
public function up()
{
Schema::table('books', function(Blueprint $table){
$table->softDeletes();
});
}
public function down()
{
Schema::table('books', function(Blueprint $table){
$table->dropColumn('deleted_at');
});
}
3) Run the migration
$ php artisan migrate
4) Open the Book model and add the SoftDelete trait
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Book extends Model {
use SoftDeletes;
protected $dates = ['deleted_at'];
}
5) The next time you delete a record associated with this model, the deleted_at column will be set to the current timestamp.
Any record having a set deleted_at timestamp will not be included in any retrieved results.
6) If you need to include the soft deleted record in any eloquent query result, you can use the withTrashed method:
$Books = Book::withTrashed()->get();
You see find here the official documentation:

Laravel already did it look here so you add deleted_at in your model and
as docs said your model is like:
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Flight extends Model
{
use SoftDeletes;
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = ['deleted_at'];
}

When you want to soft delete actually you need a flag. Let's say that in your table you have a column deleted which accepts boolean values.
When you retrieve the data in your controller to pass it to the view then you will query the table you just put a where clause to your query something like:
->where('deleted',0)
So you get the "undeleted" items.
Now when you want to softdelete actually you don't delete but you update your column to set it's status to 1.

Use this: Documentation soft deleting
later add to the conditions for downloading items
->whereNull('deleted_at')

Laravel has it's own implementation of soft deleting. Simply add use SoftDeletes to your model, and it starts working. Try reading Eloquent - Soft deletes to learn more about it and its implications on your code.

You must add a field to soft delete when creating the table. It's best to migrate. If it will be and you'll use soft delete then:
$ item-> delete () - will be softdelete
$ item-> forcedelete () - will permanently delete

1) For add column to default user table:
`php artisan make:migration add_column_delete_soft --table="user"`(if already migrate)
-add above migration inside
$table->SoftDeletes();
-if not migrate then follow this step:
1) add `$table->SoftDeletes()`; in create_user migration then follow below process as same.
2) Put in Model/User.php
-put below package:
use Illuminate\Database\Eloquent\SoftDeletes;
-add below line:
use SoftDeletes;
-Add below line after $fillable:
protected $dates = ['deleted_at'];
3) Add Controller inside delete method as you want to delete.
public function delete(Request $request)
{
User::where('email', $request->email)->delete();
}
4) if you want to return Null then follow below steps:
Route inside:
// soft delete data again null
Route::get('restore/{id}', [AuthController::class, 'restoredata']);
Controller inside:
public function restoredata(Request $request, $id)
{
User::onlyTrashed()->find($id)->restore();
return 'deleted null Successfully';
}
For delete all data from database(not soft delete)
-do in controller
$delete_data = User::where('email', $request->email)->forceDelete();

Related

Eloquent model is returning as builder

I'm relearning Laravel with laravel 7 and have hit an issue where I'm unable to query a record in my database table. So instead of a call like $test = Test::find_by_id_and_name(1, 'test 1'); (and also $test = Test::where('id', 1); returning a class of Illuninate\Database\Eloquent\Model it returns a class of Illuminate\Database\Eloquent\Builder.
I have created a Migration for a table called Tests and seeded it with a few rows of test data. The Test Model in App is as follows
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Test extends Model
{
protected $guarded = [];
use SoftDeletes;
}
the Migration is:
se Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTestsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('tests', function (Blueprint $table) {
$table->id();
$table->string( 'name' );
$table->string( 'url', 255 );
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('tests');
}
}
So anyone any idea why I'm not getting the Model I need so i can do for instance a dd($test); and see the values stored in the database for the row with the id of 1? or even do an echo($test->name); and see the name of this item?
thanks
* ADDITIONAL *
Should of pointed out my initial code had Test::find_by_id_and_name(1, 'test 1'); but this didn't work and throw an exception about finding the class. I modified if with where and above was a typo as it was where( 'id', 1 ); (I've corrected the code using my initial find_by code). Adding a get() or any other thing now returns null. I have verified that the database contains the table tests and that an item with the id and name of 'test 1' exists
* RESULT *
The underlying issue in the end was the data, the url had https::// in it (additional colon) so indeed it would return null. Thanks guys helped me find the reason.
Misunderstanding of query builder vs models in Laravel. Check doc for reference.
Calling query builder method statically on a model returns a builder.
User::where('id', 1); // returns builder
To resolve a query builder you can either use get() or first().
User::where('id', 1)->get(); // Returns a collection of users with 1 element.
User::where('id', 1)->first(); // Returns one user.
You can also fetch the user out of the collections this is not recommended as you might as well just call first().
User::where('id', 1)->get()->first(); // Returns collection fetches first element that is an user.
Laravel has static methods for finding models by id.
User::find(1); // returns user or null
User::findOrFail(1); // returns user or exception
Try to use the following
$test = Test::find(1);
Then you will get the record,

Laravel delete by BelongsToMany relationship

I have a Task class. And each record of this table can have one or many childs and can be one or many parents of another task.
Table tasks
id | name
Table tasks_links
parent_id | child_id
Task model
<?php
namespace App;
class Task extends Model
{
public function childs()
{
return $this->belongsToMany(Task::class, 'tasks_links', 'parent_id','child_id');
}
public function parents()
{
return $this->belongsToMany(Task::class, 'tasks_links' , 'child_id' , 'parent_id');
}
}
And in my controller and views
I can use the relationship like
Task::find($id)->parents(); //Return an array
When I delete a task, I would also to delete the links with other related tasks
So the following is working :
\DB::table('tasks_links')->where('parent_id' , $task->id)->delete();
\DB::table('tasks_links')->where('child_id' , $task->id)->delete();
But I the following is not working
foreach ($task->parents() as $parent) {
$parent->delete();
}
Is there any way to delete the links by using the parents and childs functions instead of searching directly in the database ?
$task =Task::find($id);
$task->childs()->detach();
$task->parents()->detach();
$task->delete();
The fastest way of doing this.. if every time you delete a task you will want to delete all relations you should just include this in your task migrations
$table->foreign('the_foreign_key')->references('related_table_primary_key')->on('table_name_related')->onDelete('cascade');
Every time you delete a task on relationships will be deleted.
What I usually do on these situations is, when designing the database, I write a migration and set what columns I want to be affected by cascade.
Example
php artisan make:migration cascade_implementation
and on the Up() I set whatever I wish to be affected, on Down() I set the inverse, in case of a rollback needed. In your case, something like (or the other way around, depending on your needs):
public function up()
{
Schema::table('tasks', function (Blueprint $table) {
$table->foreign('parent_id')
->references('id')->on('tasks_links')
->onDelete('cascade');
$table->foreign('child_id')
->references('id')->on('tasks_links')
->onDelete('cascade');
});
}
Read more at https://laravel.com/docs/5.5/migrations

Laravel 5 Eloquent-BelongsTo hasMany give me empty object

I come here cause i have an issue with Eloquent relations One To Many, i've tested a lot since a week now but nothing to do. I try here for my last chance, after this, i will try Database: Query Builder, but i will prefer to perform my code with Eloquent.
To make simple, i want to show the differents furnitures use with the id task, so a task hasMany furnitures.
So i give you the problem, i made the relation into my model, when i call the function HasMany, it's returned to me an empty object...
I use php artisan tinker on git bash but after a thousand of try, it's not working.
I show you my try with GitBash and after my code.
When i do this ">>> $comments = App\BonIntervention::find(2003);"
Tinker show me the right thing, the id "2003" to my Table related to my model, with all his components. But when i do this after:
"$comment = $comments->bonInterventionFournitures"
I'have this answer "Illuminate\Database\Eloquent\Collection {#810
all: [],
}"
And for a lot of try with different name/method his always the same, like my table are empty, but they're not....
Here you have my model for the "task", When i read the doc Laravel eloquent HastoMany, it appears that you can pass to the return, for the first parameter the namespace, for the second parameter the foreign key of the table, and for third parameter the primary key. So i did like this, i hope i didn't mistake myself.
namespace App;
use Illuminate\Database\Eloquent\Model;
class BonIntervention extends Model
{
protected $primaryKey = 'Id_TTa';
protected $table = 'T_Taches';
public $timestamps = false;
public function bonInterventionFournitures(){
return $this->hasMany('App\BonInterventionFournitures', 'Id_TTa', 'Id_TTaDFo');
}
}
Now it's the model for furnitures. (Same method for the parameters in the return)
namespace App;
use Illuminate\Database\Eloquent\Model;
class BonInterventionFournitures extends Model
{
protected $table = 'T_Taches_Details_Fournitures';
protected $primaryKey = 'Id_TTaDFo';
public function bonInterventions(){
return $this->belongsTo('App\BonIntervention', 'Id_TTa', 'Id_TTa');
}
}
I can show you my migrations for this table.
First, the table task (i not show you the entire table, because it's a lot of information.
public function up()
{
Schema::create('T_Taches', function(Blueprint $table)
{
$table->integer('Id_TTa', true);
$table->string('Responsable_TCa')->nullable()->index('Responsable_TCa');
$table->dateTime('Date_TTa')->nullable()->default('0000-00-00 00:00:00');
$table->string('Ste_TCl')->nullable()->index('Ste_TCl');
$table->string('Ste_Utl')->nullable()->index('Ste_Utl');
$table->string('Adr_Liv_TCl')->nullable()->index('Adr_Liv_TCl');
$table->string('Contact_TCo')->nullable()->index('Contact_TCo');
$table->string('Collaborateur_TCa')->nullable()->index('Collaborateur_TCa');
$table->string('NDevis_TDv')->nullable()->index('NDevis_TDv');
$table->string('Devis_Type_TTa')->nullable();
$table->string('NCommande_TDv')->nullable()->index('NCommande_TDv');
$table->dateTime('Date_Debut_TTa')->nullable();
$table->dateTime('Date_Fin_TTa')->nullable();
$table->dateTime('Date_Demande_TTa')->nullable();
Now the furnitures table
public function up()
{
Schema::create('T_Taches_Details_Fournitures', function(Blueprint $table)
{
$table->integer('Id_TTaDFo', true);
$table->integer('Id_TTa')->nullable()->index('Id_TTa');
$table->string('Class_TTaDFo')->nullable();
$table->string('Des_TTaDFo')->nullable();
$table->string('Ref_TTaDFo')->nullable();
$table->float('Qte_TTaDFo', 10, 0)->nullable()->default(0);
$table->float('PAHT_TTaDFo', 10, 0)->nullable()->default(0);
$table->float('Tx_Mge_TTaDFo', 10, 0)->nullable()->default(1.5);
$table->float('Vente_HT_TTaDFo', 10, 0)->nullable()->default(0);
});
}
I hope you understand my question, and thanks all for watching.
SOLVED
I solved this and i explain why on the answer, after my post.
I've found the solution. In fact in my models i erase the second and third parameters.
return $this->belongsTo('App\BonIntervention', 'Id_TTa', 'Id_TTa');
return $this->hasMany('App\BonInterventionFournitures', 'Id_TTa', 'Id_TTaDFo');
I just add the second parameter in my return hasMany, just like this
return $this->hasMany('App\BonInterventionFournitures', 'Id_TTa');
return $this->belongsTo('App\BonIntervention');
Now with artisan tinker when i do this
$comments = App\BonIntervention::find(2003);
$comment = $comments->bonInterventionFournitures;
I find the right answer.

How to soft delete related records when soft deleting a parent record in Laravel?

I have this invoices table that which has the following structure
id | name | amount | deleted_at
2 iMac 1500 | NULL
and a payments table with the following structure
id | invoice_id | amount | deleted_at
2 2 1000 | NULL
Invoice Model
class Invoice extends Model {
use SoftDeletes;
}
here's the code to delete the invoice
public function cance(Request $request,$id)
{
$record = Invoice::findOrFail($id);
$record->delete();
return response()->json([
'success' => 'OK',
]);
}
Payments model
class Payment extends Model {
use SoftDeletes;
}
The softDelete on Invoice table works perfectly but its related records (payments) still exists.How do I delete them using softDelete?
Eloquent doesn't provide automated deletion of related objects, therefore you'll need to write some code yourself. Luckily, it's pretty simple.
Eloquent models fire different events in different stages of model's life-cycle like creating, created, deleting, deleted etc. - you can read more about it here: http://laravel.com/docs/5.1/eloquent#events. What you need is a listener that will run when deleted event is fired - this listener should then delete all related objects.
You can register model listeners in your model's boot() method. The listener should iterate through all payments for the invoice being deleted and should delete them one by one. Bulk delete won't work here as it would execute SQL query directly bypassing model events.
This will do the trick:
class MyModel extends Model {
protected static function boot() {
parent::boot();
static::deleted(function ($invoice) {
$invoice->payments()->delete();
});
}
}
You can go one of 2 ways with this.
The simplest way would be to override Eloquents delete() method and include the related models as well e.g.:
public function delete()
{
$this->payments()->delete();
return parent::delete();
}
The above method should work just find but it seems a little bit dirty and I'd say it's not the preferred method within the community.
The cleaner way (IMO) would be to tap into Eloquents events e.g.:
public static function boot()
{
parent::boot();
static::deleting(function($invoice) {
$invoice->payments()->delete();
});
}
Either (but not both) of the above methods would go in your Invoice model.
Also, I'm assuming that you have your relationships set up in your model, however, I'm not sure if you allow multiple payments for one invoice. Either way you might need to change the payments() in the examples to whatever you've named the relationship in your invoice model.
Hope this helps!
I know you asked this question a long time ago but I found this package to be very simple and straightforward.
Or you can use this package it's useful too.
Remember to install the right version depending on your laravel version.
You must install it via composer:
composer require askedio/laravel5-soft-cascade ^version
In second package:
composer require iatstuti/laravel-cascade-soft-deletes
Register the service provider in your config/app.php.
you can read the docs on the GitHub page.
If you delete a record this package recognizes all of its children and soft-delete them as well.
If you have another relationship in your child model use its trait in that model as well. its so much easier than doing it manually.
The second package has the benefit of deleting grandchildren of the model. in some cases, I say its a better approach.
If the relationship of your database does not go any further than only one layer, then you could simply use Laravel events to handle your soft-deletes within the Model boot() method as follow:
<?php
//...
protected static boot() {
parent::boot();
static::deleting(function($invoice) {
$invoice->payments()->delete();
});
}
If, however, your structure goes deeper than only one layer, you will have to tweak that piece of code.
Let's say for example you don't want to remove the payments of an invoice but rather the whole payment history of a given user.
<?php
// ...
class Invoice extends Model
{
// ...
/**
* Holds the methods names of Eloquent Relations
* to fall on delete cascade or on restoring
*
* #var array
*/
protected static $relations_to_cascade = ['payments'];
protected static boot()
{
parent::boot();
static::deleting(function($resource) {
foreach (static::$relations_to_cascade as $relation) {
foreach ($resource->{$relation}()->get() as $item) {
$item->delete();
}
}
});
static::restoring(function($resource) {
foreach (static::$relations_to_cascade as $relation) {
foreach ($resource->{$relation}()->get() as $item) {
$item->withTrashed()->restore();
}
}
});
}
public function payments()
{
return $this->hasMany(Payment::class);
}
}
<?php
// ...
class User extends Model
{
// ...
/**
* Holds the methods names of Eloquent Relations
* to fall on delete cascade or on restoring
*
* #var array
*/
protected static $relations_to_cascade = ['invoices'];
protected static boot()
{
parent::boot();
static::deleting(function($resource) {
foreach (static::$relations_to_cascade as $relation) {
foreach ($resource->{$relation}()->get() as $item) {
$item->delete();
}
}
});
static::restoring(function($resource) {
foreach (static::$relations_to_cascade as $relation) {
foreach ($resource->{$relation}()->get() as $item) {
$item->withTrashed()->restore();
}
}
});
}
public function invoices()
{
return $this->hasMany(Invoice::class);
}
}
This paradigm ensures Laravel to follow the rabbit hole no matter how deep it goes.
You can use Model Observers as well:
php artisan make:Observer InvoiceOberser --model=Invoice
It will create a new file in /app/Observers/InvoiceObserver.php with the following methods:
created
updated
deleted
restored
forceDeleted
You just need to update the deleted method to this:
public function deleted(Invoice $invoice)
{
$invoice->payments()->delete();
}
And finally in /app/Providers/EventServiceProvider.php add this lines:
// On the top
use App\Models\Invoice;
use App\Observers\InvoiceObserver;
// On boot method
Invoice::observe(InvoiceObserver::class);

Laravel Soft Delete posts

in our project we must be use soft delete for each posts. in laravel document i think we can only use this feature for tables.
can we use that for posts on table such as
$id = Contents::find($id);
$id->softDeletes();
Updated Version (Version 5.0 & Later):
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model {
use SoftDeletes;
protected $table = 'posts';
// ...
}
When soft deleting a model, it is not actually removed from your
database. Instead, a deleted_at timestamp is set on the record. To
enable soft deletes for a model, specify the softDelete property on
the model (Documentation).
For (Version 4.2):
use Illuminate\Database\Eloquent\SoftDeletingTrait; // <-- This is required
class Post extends Eloquent {
use SoftDeletingTrait;
protected $table = 'posts';
// ...
}
Prior to Version 4.2 (But not 4.2 & Later)
For example (Using a posts table and Post model):
class Post extends Eloquent {
protected $table = 'posts';
protected $softDelete = true;
// ...
}
To add a deleted_at column to your table, you may use the softDeletes
method from a migration:
For example (Migration class' up method for posts table) :
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('posts', function(Blueprint $table)
{
$table->increments('id');
// more fields
$table->softDeletes(); // <-- This will add a deleted_at field
$table->timeStamps();
});
}
Now, when you call the delete method on the model, the deleted_at column will be set to the current timestamp. When querying a model that uses soft deletes, the "deleted" models will not be included in query results. To soft delete a model you may use:
$model = Contents::find( $id );
$model->delete();
Deleted (soft) models are identified by the timestamp and if deleted_at field is NULL then it's not deleted and using the restore method actually makes the deleted_at field NULL. To permanently delete a model you may use forceDelete method.
You actually do the normal delete. But on the model you specify that its a softdelete model.
So on your model add the code:
class Contents extends Eloquent {
use SoftDeletingTrait;
protected $dates = ['deleted_at'];
}
Then on your code do the normal delete like:
$id = Contents::find( $id );
$id ->delete();
Also make sure you have the deleted_at column on your table.
Or just see the docs: http://laravel.com/docs/eloquent#soft-deleting
I just did this with Laravel 8 and it worked. It's basically what #The alpha said, but trying to wrap everything quicker. Follow this steps.
In the migration file add:
$table->softDeletes();
In the model:
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model
{
use SoftDeletes;
...
];
}
In the controller:
$user->delete();
Bonus: if you need to restore the deleted user
User::withTrashed()->find($id);->restore();
Just an update for Laravel 5:
In Laravel 4.2:
use Illuminate\Database\Eloquent\SoftDeletingTrait;
class Post extends Eloquent {
use SoftDeletingTrait;
protected $dates = ['deleted_at'];
}
becomes in Laravel 5:
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model {
use SoftDeletes;
protected $dates = ['deleted_at'];
In Laravel 5.5 Soft Deleted works ( for me ).
Data Base
deleted_at Field, default NULL value
Model
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model {
use SoftDeletes;
}
Controller
public function destroy($id)
{
User::find($id)->delete();
}
In the Latest version of Laravel i.e above Laravel 5.0. It is quite simple to perform this task.
In Model, inside the class just write 'use SoftDeletes'. Example
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model
{
use SoftDeletes;
}
And In Controller, you can do deletion. Example
User::where('email', 'youremail#example.com')->delete();
or
User::where('email', 'youremail#example.com')->softDeletes();
Make sure that you must have 'deleted_at' column in the users Table.
Here is the details from laravel.com
http://laravel.com/docs/eloquent#soft-deleting
When soft deleting a model, it is not actually removed from your database. Instead, a deleted_at timestamp is set on the record. To enable soft deletes for a model, specify the softDelete property on the model:
class User extends Eloquent {
protected $softDelete = true;
}
To add a deleted_at column to your table, you may use the softDeletes method from a migration:
$table->softDeletes();
Now, when you call the delete method on the model, the deleted_at column will be set to the current timestamp. When querying a model that uses soft deletes, the "deleted" models will not be included in query results.

Categories