Welcome back! In the previous lessons, you learned how to create a fundamental MVC ToDo application using PHP Laravel, with capabilities to list, add, and delete items. Now, we're going to enhance this application by introducing functionality that allows users to update existing ToDo items. This addition will grant users the flexibility to modify the details of a task whenever there are changes, ensuring the ToDo list accurately reflects their current needs.
In this lesson, we will add the functionality to edit and update ToDo items within your Laravel application. You will learn how to create an editing interface, handle user inputs, and update the stored data seamlessly. Here's a quick overview of the essential code snippets and their roles in this functionality:
Let's start by the view that lists all ToDo items and provides an edit button for each item:
php1<!-- app/resources/views/todos/index.blade.php --> 2 3@extends('layouts.app') 4 5@section('content') 6<h1>ToDo List</h1> 7<ul> 8 @foreach($todos as $todo) 9 <li>{{ $todo->title }} - {{ $todo->description }} 10 <a href="/todos/{{ $todo->id }}/edit">Edit</a> 11 <form action="/todos/{{ $todo->id }}" method="post" style="display: inline;"> 12 @csrf 13 @method('DELETE') 14 <button type="submit">Delete</button> 15 </form> 16 </li> 17 @endforeach 18</ul> 19 20<form action="/todos" method="post"> 21 @csrf 22 <input type="text" name="title" placeholder="Title" required> 23 <input type="text" name="description" placeholder="Description"> 24 <button type="submit">Add ToDo</button> 25</form> 26@endsection
In the view we have an unordered list that displays all ToDo items. Each item has an "Edit" link that directs users to the edit form for that specific item. The form also includes a "Delete" button that allows users to remove the item from the list.
Wondering what users will see when they click the "Edit" link? Let's take a look at the controller method that handles the edit request:
php1// app/app/Http/Controllers/TodoController.php 2 3class TodoController 4{ 5 ... 6 public function edit($id) 7 { 8 $todo = $this->todoService->findOne($id); 9 return view('todos.edit', ['title' => 'Edit Todo', 'todo' => $todo]); 10 } 11}
This method retrieves the ToDo item with the specified ID and passes it to the edit view. The view will display the item's current details and provide a form for users to update the information. Let's take a look at the edit view:
php1<!-- app/resources/views/todos/edit.blade.php --> 2@extends('layouts.app') 3 4@section('content') 5<h1>Edit ToDo</h1> 6<form action="/todos/{{ $todo->id }}" method="post"> 7 @csrf 8 @method('PATCH') 9 <input type="text" name="title" value="{{ $todo->title }}" required> 10 <input type="text" name="description" value="{{ $todo->description }}"> 11 <button type="submit">Update ToDo</button> 12</form> 13@endsection
The edit view displays the current title and description of the ToDo item in input fields. Users can modify these fields and submit the form to update the item. The form uses the PATCH
method to send the update request to the server.
Now, let's take a look at the controller method that handles the update request:
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 show($id) 23 { 24 $todo = $this->todoService->findOne($id); 25 return view('todos.show', ['title' => 'Todo Details', 'todo' => $todo]); 26 } 27 28 public function store(Request $request) 29 { 30 $request->validate([ 31 'title' => 'required|string|max:255', 32 'description' => 'nullable|string|max:255', 33 ]); 34 35 $this->todoService->create($request->title, $request->description); 36 return redirect('/todos'); 37 } 38 39 public function edit($id) 40 { 41 $todo = $this->todoService->findOne($id); 42 return view('todos.edit', ['title' => 'Edit Todo', 'todo' => $todo]); 43 } 44 45 public function update(Request $request, $id) 46 { 47 $request->validate([ 48 'title' => 'required|string|max:255', 49 'description' => 'nullable|string|max:255', 50 ]); 51 52 $this->todoService->update($id, $request->title, $request->description); 53 return redirect('/todos'); 54 } 55 56 public function destroy($id) 57 { 58 $this->todoService->delete($id); 59 return redirect('/todos'); 60 } 61}
This is the same controller we've been working with, but we've added a new method called update
. This method handles the update request by validating the user input, calling the update
method on the TodoService
, and redirecting the user back to the ToDo list view.
Finally, let's take a look at the TodoService
class, which contains the update
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 update($id, $title, $description) 53 { 54 $todos = $this->findAll(); 55 56 foreach ($todos as $todo) { 57 if ($todo->id == $id) { 58 $todo->title = $title; 59 $todo->description = $description; 60 } 61 } 62 63 File::put($this->filePath, json_encode($todos, JSON_PRETTY_PRINT)); 64 } 65 66 public function delete($id) 67 { 68 $todos = $this->findAll(); 69 $todos = array_filter($todos, function($todo) use ($id) { 70 return $todo->id != $id; 71 }); 72 73 File::put($this->filePath, json_encode(array_values($todos), JSON_PRETTY_PRINT)); 74 } 75}
The update
method in the TodoService
class iterates over all ToDo items, finds the item with the specified ID, and updates its title and description. The updated list of ToDo items is then saved back to the JSON file.
Finally, let's see what are the routes that we need to add to the 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']); 9Route::get('/todos/{id}/edit', [TodoController::class, 'edit']); 10Route::patch('/todos/{id}', [TodoController::class, 'update']);
As you see, we've added two new routes: one for handling the edit request to display the edit form and another for handling the update request to update the ToDo item using the PATCH
method.
Notice, that the first one uses GET
method since it is only responsible for showing the form, which is necessary for providing new values for the ToDo item. The second one uses PATCH
method, since it is responsible for updating the ToDo item based on the provided values.
That's it! You've successfully implemented the functionality to edit and update ToDo items in your Laravel application. Users can now modify the details of existing tasks, ensuring that their ToDo list remains accurate and up-to-date.
Updating items is a critical function for most applications since the details of tasks often change. Imagine planning a project where deadlines shift or new notes must be added — having edit capabilities is a significant usability and functionality boost. By learning how to implement these features, you will gain a deeper understanding of the MVC pattern and improve your skills in building dynamic, responsive web applications. These skills are not only essential for enhancing your current project but also valuable for any future applications you might build.
Ready to enhance your ToDo app further? Let's continue to the practice section, where you can implement and test these features on your own!