In this lesson, you will learn how to allow users to create new ToDo items in your Laravel application. You will achieve this by:
- Updating the view to include a form where users can enter new ToDo items.
- Modifying the TodoController to handle form submissions and validate user input.
- Enhancing the TodoService to save the new ToDo items in a persistent manner.
Let's start with the view, that is used to capture user input for creating new ToDo items.
<!-- app/resources/views/todos/index.blade.php -->
<form action="/todos" method="post">
@csrf
<input type="text" name="title" placeholder="Title" required>
<input type="text" name="description" placeholder="Description">
<button type="submit">Add ToDo</button>
</form>
This form will capture the user's input - a title and an optional description - and submit it to the ``/todos` endpoint. The @csrf directive generates a hidden input field with a CSRF token, which is required to protect your application from cross-site request forgery (CSRF) attacks.
You'll update your TodoController to look like this:
// app/app/Http/Controllers/TodoController.php
<?php
namespace App\Http\Controllers;
use App\Services\TodoService;
class TodoController extends Controller
{
protected $todoService;
public function __construct(TodoService $todoService)
{
$this->todoService = $todoService;
}
public function index()
{
$todos = $this->todoService->findAll();
return view('todos.index', ['title' => 'ToDo List', 'todos' => $todos]);
}
public function show($id)
{
$todo = $this->todoService->findOne($id);
return view('todos.show', ['title' => 'Todo Details', 'todo' => $todo]);
}
public function store(Request $request)
{
$request->validate([
'title' => 'required|string|max:255',
'description' => 'nullable|string|max:255',
]);
$this->todoService->create($request->title, $request->description);
return redirect('/todos');
}
}
We have a new method, called store, that handles the form submission. Let's see how it works:
- The method receives a Request object, which contains the user's input - the title and description of the new ToDo item.
- We use the
validate method to ensure that the user's input is valid. The title is required and must be a string of up to 255 characters, while the description is optional and can be up to 255 characters long. The rules are defined using Laravel's validation syntax, which provides a convenient way to validate user input.
- If the input is valid, we use the TodoService to create a new ToDo item passing the provided title and description.
- Finally, we redirect the user back to the ToDo list page, where they can see the newly added item.
Let's now see how actual data persistence is handled in the TodoService:
// app/app/Services/TodoService.php
<?php
namespace App\Services;
use Illuminate\Support\Facades\File;
class TodoService
{
protected $filePath;
public function __construct()
{
// Set the file path to store the todos (in storage folder)
$this->filePath = storage_path('app/todos.json');
}
public function findAll()
{
// Check if the file exists using File facade
if (File::exists($this->filePath)) {
// Read and decode the file content as objects
$todos = json_decode(File::get($this->filePath), false);
} else {
// If the file doesn't exist, initialize with an empty array
$todos = [];
}
return $todos;
}
public function findOne($id)
{
$todos = $this->findAll();
return collect($todos)->firstWhere('id', $id);
}
public function create($title, $description = null)
{
// Get the current todos
$todos = $this->findAll();
// Create a new todo with incremented ID
$newTodo = (object)[
'id' => count($todos) + 1,
'title' => $title,
'description' => $description
];
// Append the new todo to the list
$todos[] = $newTodo;
// Save the updated todos list back to the file using File facade
File::put($this->filePath, json_encode($todos, JSON_PRETTY_PRINT));
return $newTodo;
}
}
You might notice, that the logic for creating and stoting ToDo items has been changed. We were using hardcoded data in the previous courses, but right now we are storing the data in a JSON file. This is because arrays in PHP are not persistent and will be lost when the application is restarted. By storing the data in a file, we can ensure that the ToDo items persist across requests and server restarts.
To accomodate this change, we have updated the TodoService to read and write ToDo items from a JSON file:
- The constructor sets the file path to store the ToDo items in the
storage/app directory.
- The
findAll method reads the ToDo items from the file and returns them as an array of objects using the json_decode function.
Now that you understood how the data is stored, let's see how the create method works:
- The method receives the title and an optional description of the new ToDo item.
- The current ToDo items are loaded using the
findAll method.
- The new ToDo item is created as an object with an incremented ID, title, and description.
- The new ToDo item is appended to the list of ToDo items.
- The updated list of ToDo items is saved back to the file using the
File::put method.
- Finally, the new ToDo item is returned to the caller.
Let's now see what new route we need to add to the web.php file:
// app/routes/web.php
<?php
use App\Http\Controllers\TodoController;
Route::get('/todos', [TodoController::class, 'index']);
Route::get('/todos/{id}', [TodoController::class, 'show']);
Route::post('/todos', [TodoController::class, 'store']);
We have added a new route that listens for POST requests to the /todos endpoint. When a user submits the form to create a new ToDo item, the request will be handled by the store method in the TodoController. Pay attention, that for the POST requests we use the Route::post method instead of Route::get.
That's it! You have successfully added the functionality to create new ToDo items in your application. Users can now add tasks to their ToDo list using the form you provided. This feature enhances the interactivity and usability of your application, making it more dynamic and engaging for users.