Courses

[FREE] Laravel 11 For Beginners: Your First Project

Route Parameters and Route Model Binding

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...