Welcome back! In the previous lesson, you learned how to create new ToDo items in your Laravel application. Now, we're going to take another important step: adding the capability to delete ToDo items. This feature is essential for maintaining an up-to-date and clutter-free task list. By the end of this lesson, you'll know how to implement a deletion feature that allows users to efficiently remove items they no longer need.
In this lesson, we'll cover how to allow users to delete ToDo items from your application. You will achieve this by:
- Updating the view to include a delete button for each ToDo item.
- Modifying the
TodoController
to handle delete requests. - Enhancing the
TodoService
to update your storage by removing deleted items.
Here's an example of how your view will be structured with a delete button:
HTML, XML1<!-- app/resources/views/todos/index.blade.php --> 2 3<ul> 4 @foreach($todos as $todo) 5 <li>{{ $todo->title }} - {{ $todo->description }} 6 <form action="/todos/{{ $todo->id }}" method="post" style="display: inline;"> 7 @csrf 8 @method('DELETE') 9 <button type="submit">Delete</button> 10 </form> 11 </li> 12 @endforeach 13</ul>
This form includes a delete button that submits the form when clicked, triggering a deletion request to the server. Note that in HTML forms, the only HTTP methods allowed are GET
and POST
. Since we need a DELETE
request for removing resources, Laravel provides the @method('DELETE')
directive to simulate this by overriding POST
with DELETE
. When the form is submitted, Laravel interprets the request as a DELETE
action, allowing us to handle it appropriately in the controller.
Why not use a GET
request? Because GET
requests should not be used for destructive actions, such as deleting data. Instead, we use DELETE
requests to indicate that the server should remove the specified resource.
You'll also modify your TodoController
to include a delete method:
php1// app/app/Http/Controllers/TodoController.php 2 3<?php 4namespace App\Http\Controllers; 5use App\Services\TodoService; 6 7class TodoController extends Controller 8{ 9 protected $todoService; 10 11 public function __construct(TodoService $todoService) 12 { 13 $this->todoService = $todoService; 14 } 15 16 public function index() 17 { 18 $todos = $this->todoService->findAll(); 19 return view('todos.index', ['title' => 'ToDo List', 'todos' => $todos]); 20 } 21 22 public function store(Request $request) 23 { 24 $request->validate([ 25 'title' => 'required|string|max:255', 26 'description' => 'nullable|string|max:255', 27 ]); 28 29 $this->todoService->create($request->title, $request->description); 30 return redirect('/todos'); 31 } 32 33 public function destroy($id) 34 { 35 $this->todoService->delete($id); 36 return redirect('/todos'); 37 } 38}
We have a new destroy
method in the controller, which calls the delete
method on the TodoService
to remove the specified ToDo item. After deleting the item, the user is redirected back to the updated ToDo list.
Finally, you'll need to update the TodoService
to include the delete
method:
php1// app/app/Services/TodoService.php 2 3<?php 4namespace App\Services; 5use Illuminate\Support\Facades\File; 6use Illuminate\Support\Str; 7 8class TodoService 9{ 10 protected $filePath; 11 12 public function __construct() 13 { 14 $this->filePath = storage_path('app/todos.json'); 15 } 16 17 public function findAll() 18 { 19 if (File::exists($this->filePath)) { 20 $todos = json_decode(File::get($this->filePath), false); 21 } else { 22 $todos = []; 23 } 24 25 return $todos; 26 } 27 28 public function findOne($id) 29 { 30 $todos = $this->findAll(); 31 return collect($todos)->firstWhere('id', $id); 32 } 33 34 public function create($title, $description = null) 35 { 36 $todos = $this->findAll(); 37 38 // Generate a random UUID for each new ToDo item 39 $newTodo = (object)[ 40 'id' => (string) Str::uuid(), 41 'title' => $title, 42 'description' => $description 43 ]; 44 45 $todos[] = $newTodo; 46 47 File::put($this->filePath, json_encode($todos, JSON_PRETTY_PRINT)); 48 49 return $newTodo; 50 } 51 52 public function delete($id) 53 { 54 $todos = $this->findAll(); 55 $todos = array_filter($todos, function($todo) use ($id) { 56 return $todo->id != $id; 57 }); 58 59 File::put($this->filePath, json_encode(array_values($todos), JSON_PRETTY_PRINT)); 60 } 61}
The delete
method in the TodoService
removes the ToDo item with the specified ID from the storage file. It uses the array_filter
function to filter out the item with the matching ID. After removing the item, the service writes the updated list back to the storage file.
Notice, that during the creation process, we generate a random UUID for each new ToDo item using the Str::uuid()
function. UUIDs (Universally Unique Identifiers) are used to ensure each item has a distinct identifier across all ToDo items. This is more robust than incrementing IDs, as it avoids issues when items are deleted or created simultaneously, which could result in ID conflicts. UUIDs are globally unique, making them a reliable choice for identifying resources in distributed systems and large applications.
Finally, let's define the route for the destroy
method in the routes/web.php
file:
php1// app/routes/web.php 2 3<?php 4use App\Http\Controllers\TodoController; 5 6Route::get('/todos', [TodoController::class, 'index']); 7Route::post('/todos', [TodoController::class, 'store']); 8Route::delete('/todos/{id}', [TodoController::class, 'destroy']);
Now, when a user clicks the delete button on a ToDo item, the form sends a DELETE
request to the server, which is handled by the destroy
method in the TodoController
. Notice, that we use the Route::delete
method to define the route for handling DELETE
requests.
With this implementation, users can now delete ToDo items from the list, keeping their task list organized and up-to-date. Congratulations on adding this essential feature to your application!
Developing an application with robust data management features requires both the creation and deletion of items. With a delete feature, users have the freedom to manage their tasks fully by removing items that are no longer necessary. This capability enhances the user experience, making the application not only functional but also practical and user-friendly.
Moreover, implementing a delete feature introduces vital concepts such as handling different HTTP request types, enhancing your understanding of RESTful services. It lays the groundwork for data manipulation operations, which are paramount in most web applications. Are you ready to make your ToDo app even more interactive? Let's dive into the practice section and implement the delete feature together!