Laravel Route Resources
Sunday, November 3, 2024
// 3 min read
Table of Contents
Route resources provide a convenient way to generate multiple route definitions for CRUD actions with a single line of code.
In this post, we will explore the basic setup and options that resources offer.
Resource Controller
First, you need to have a controller prepared with the CRUD methods. Luckily, Laravel has a command out of the box that generates a resource controller for you.
php artisan make:controller PostController --resource --model=Post
This command will generate the skeleton of the resource controller. While the --model
option is recommended, it can be omitted. It is useful if you want to type-hint the model instance in the related methods.
For example, this is what it generates for the show method:
public function show(Post $post)
{
//
}
If you do not specify the --model
it generates the following:
public function show(string $id)
{
//
}
You will need to customize the controller to fit your needs. Here is my simple PostController
after editing each method.
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
$posts = Post::published()->latest()->paginate($request->input('limit', 10));
return view('posts.index', compact('posts'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
return view('posts.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
'is_published' => 'boolean',
]);
Post::create($request->all());
return redirect()->route('posts.index');
}
/**
* Display the specified resource.
*/
public function show(Post $post)
{
return view('posts.show', compact('post'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Post $post)
{
return view('posts.edit', compact('post'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Post $post)
{
$request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
'is_published' => 'boolean',
]);
$post->update($request->all());
return redirect()->route('posts.index');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index');
}
}
Registering Route Resource
To register a route resource, define the resource route in your routes/web.php
file like this:
Route::resource('posts', PostController::class)
This single line automatically generates the following routes:
Method | URI | Action | Description |
---|---|---|---|
GET |
| index | Display a list of posts |
GET |
| create | Display a form to create a post |
POST |
| store | Save a new post to database |
GET |
| show | Display a specific post |
GET |
| edit | Show a form for editing a post |
PUT/PATCH |
| update | Update a post in the database |
DELETE |
| destroy | Delete a post from the database |
You notice that the resource also generates names for each route. The default syntax consists of a prefix followed by the method name: posts.index
Customizing Resource Routes
You may want to customize the resource routes to better fit the needs of your application.
Specifying Routes to Generate
Sometimes, you do not need the entire set of default actions. Instead, you can specify only the actions you want to use:
Route::resource('posts', PostController::class)->only(['index', 'show']);
The line above will generate only the index
and show
route definitions.
Alternatively, you can use the except
method to list the routes you want to exclude from generation:
Route::resource('posts', PostController::class)->except(['delete']);
This will generate all routes except the delete
route.
Customize Route Names
You can override the default route names. To do this, pass an array of new names for the specific routes you want to modify. Any routes not included in this array will keep their default names.
Route::resource('posts', PostController::class)->names([
'index' => 'posts.list',
'show' => 'posts.view',
'create' => 'posts.add'
]);
Naming Resource Route Parameters
By default, resource route parameters are generated based on the singular version of the resource name (e.g., /posts
becomes post
). You can override this by using the parameters
method.
Route::resource('profiles', ProfileController::class)->parameters(['profiles' => 'username']);
This will generate route definitions like: /profiles/{username}
Nested Resource Routes
Nested Resource Routes allow you to create resource routes for a child route. For example, if a post has multiple comments, and you need a controller to manage those comments. You may use "dot" notation in your route declarations:
Route::resource('posts.comments', PostCommentController::class);
This generates the following routes:
GET
/posts/{post}/comments
(index method)GET
/posts/{post}/comments/create
(create method)POST
/posts/{post}/comments
(store method)GET
/posts/{post}/comments/{comment}
(show method)GET
/posts/{post}/comments/{comment}/edit
(edit method)PUT/PATCH
/posts/{post}/comments/{comment}
(update method)DELETE
/posts/{post}/comments/{comment}
(destroy method)
And you can generate controller methods for nested routes using the controller generator command with the --parent
option.
php artisan make:controller PostCommentController --resource --model=Comment --parent=Post
Which generates this controller class:
<?php
namespace App\Http\Controllers;
use App\Models\Comment;
use App\Models\Post;
use Illuminate\Http\Request;
class PostCommentController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Post $post)
{
//
}
/**
* Show the form for creating a new resource.
*/
public function create(Post $post)
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request, Post $post)
{
//
}
/**
* Display the specified resource.
*/
public function show(Post $post, Comment $comment)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Post $post, Comment $comment)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Post $post, Comment $comment)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Post $post, Comment $comment)
{
//
}
}
API Resource Routes
When developing an API, you exclude routes that present HTML templates such as the create
and edit
. For these routes, you can use the apiResource
method.
Route::apiResource('posts', PostController::class);
This method generates only the following routes:
GET
/posts
(index method)POST
/posts
(store method)GET
/posts/{post}
(show method)PUT/PATCH
/posts/{post}
(update method)DELETE
/posts/{post}
(destroy method)
And you can use the controller generator command with the --api
option to generate your resource API controller:
php artisan make:controller PostController --resource --model=Comment --api
Here are the most important things you need to know about route resources. For more information, read my article about the basics of routing in Laravel and refer to the resource controller section of the official Laravel documentation.