Let's talk about another way of routing parameters in Laravel. We have seen how to get parameters with question marks, like ?category_id=XXXXX
. A more typical way is to have parameters inside of the URL, like domain.com/posts/1234
where 1234
is the ID of the post or some other parameter.
Let's create that page of the individual post. You will see how to get that parameter from the URL and query the data from the DB with Eloquent. Also, we will learn about a convenient Laravel function of Route Model Binding.
Controller and Route Parameter
First, let's create a Controller that will be responsible for posts.
php artisan make:controller PostController
In the Controller, we will have a show()
method with a parameter $postId
.
app/Http/Controllers/PostController.php:
class PostController extends Controller{ public function show($postId) { }}
Inside the show()
method, we will use the find()
method of the Eloquent Model and pass the $postId
to automatically find a post by its ID. Then, we will return a View called post.blade.php
and pass the $post
to it.
app/Http/Controllers/PostController.php:
use App\Models\Post; class PostController extends Controller{ public function show($postId) { $post = Post::find($postId); return view('post', compact('post')); }}
Create a View post.blade.php
: just open the about.blade.php,
do File -> Save as
, and change the middle part of the content.
resources/views/post.blade.php:
@extends('layouts.app') @section('content') <!-- Page header with logo and tagline--> <header class="py-5 bg-light border-bottom mb-4"> <div class="container"> <div class="text-center my-5"> <h1 class="fw-bolder">{{ $post->title }}</h1> </div> </div> </header> <!-- Page content--> <div class="container mb-4"> <div class="row"> <!-- Blog entries--> <div class="col-lg-12"> <p class="lead mb-0">{{ $post->text }}</p> </div> </div> </div>@endsection
Now, how do you get that into the Route? How do you use that parameter?
When defining the URL for the Route, the parameter is set inside curly braces:
Route::get('posts/{postId}', [SomeController::class, 'some_method']);
The parameter name postId
in the Route should be the same as the variable name used in the controller's method.
So, we add that route at the bottom, also giving it a name, like in the case of the previous routes.
routes/web.php:
Route::view('/', 'home')->name('home');Route::get('/', [\App\Http\Controllers\HomeController::class, 'index'])->name('home');Route::view('contact', 'contact')->name('contact');Route::view('about', 'about')->name('about'); Route::get('posts/{postId}', [\App\Http\Controllers\PostController::class, 'show'])->name('post.show');
Let's visit the URL, /posts/1
, for the first post. We should see the first post title and text!
Route Model Binding
For such cases, when the individual record is searched by its ID, Eloquent has a better solution. Instead of postId
, you can pass post
, which will be treated as an object.
routes/web.php:
Route::get('posts/{postId}', [\App\Http\Controllers\PostController::class, 'show'])->name('post.show'); Route::get('posts/{post}', [\App\Http\Controllers\PostController::class, 'show'])->name('post.show');
Then, in the Controller, you type hint that it is a post Model object and define the parameter as $post
. And then, the DB search is done automatically by Laravel under the hood. You don't need to call find()
.
app/Http/Controllers/PostController.php:
use App\Models\Post; class PostController extends Controller{ public function show($postId) public function show(Post $post) { $post = Post::find($postId); return view('post', compact('post')); }}
Refresh the page, and it should still work!
So, this way of doing routes is called Route Model Binding because it binds the Model by type hinting the Model object type with the parameter in the Route. And it will automatically show the 404 page if the record doesn't exist.
Link to the Page
Finally, use this post.show
Route and create a link to that page. We need to add it in the home.blade.php
where we loop all the posts.
resources/views/home.blade.php:
// ... <!-- Nested row for non-featured blog posts--><div class="row"> @foreach($posts as $post) <div class="col-lg-6"> <!-- Blog post--> <div class="card mb-4"> <a href="#!"><img class="card-img-top" src="https://dummyimage.com/700x350/dee2e6/6c757d.jpg" alt="..." /></a> <a href="{{ route('post.show', $post) }}"><img class="card-img-top" src="https://dummyimage.com/700x350/dee2e6/6c757d.jpg" alt="..." /></a> <div class="card-body"> <div class="small text-muted">{{ $post->created_at }}</div> <h2 class="card-title h4">{{ $post->title }}</h2> <p class="card-text">{{ $post->text }}</p> <a class="btn btn-primary" href="#!">Read more →</a> </div> </div> </div> @endforeach</div> // ...
The parameter for the Route is passed as a second argument in the route()
helper. The parameter can be passed as a whole object or explicitly passed the ID using $post->id
, that's your personal preference.
Now, on the home page, the image should link to the post. Success!
No comments or questions yet...