Chapter 3: Routing & Controllers in Zend Framework 3
In this chapter, we continue building our Blog module from Chapter 2.
You will learn how to define routes, create controllers, and connect them with views inside the Blog module.
By the end, youβll have a working /blog page with a detail view for each post.
β Introduction to Routing
- Routing maps a URL request to a specific controller and action.
- Each module has its own routes defined in
config/module.config.php. - Controllers inside the module handle the requests and return responses (usually
ViewModel).
β Defining Routes in Blog Module
// module/Blog/config/module.config.php
<?php
use Laminas\ServiceManager\Factory\InvokableFactory;
return [
'router' => [
'routes' => [
'blog' => [
'type' => 'Literal',
'options' => [
'route' => '/blog',
'defaults' => [
'controller' => Blog\Controller\PostController::class,
'action' => 'index',
],
],
'may_terminate' => true,
'child_routes' => [
'detail' => [
'type' => 'Segment',
'options' => [
'route' => '/detail[/:id]',
'constraints' => [
'id' => '[0-9]+',
],
'defaults' => [
'action' => 'detail',
],
],
],
],
],
],
],
'controllers' => [
'factories' => [
Blog\Controller\PostController::class => InvokableFactory::class,
],
],
'view_manager' => [
'template_path_stack' => [
__DIR__ . '/../view',
],
],
];
- /blog β Loads
PostController::indexAction. - /blog/detail/:id β Loads
PostController::detailActionwith a numeric ID.
β Creating PostController
// module/Blog/src/Controller/PostController.php
namespace Blog\Controller;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;
class PostController extends AbstractActionController
{
public function indexAction()
{
// Example blog posts
$posts = [
['id' => 1, 'title' => 'First Blog Post'],
['id' => 2, 'title' => 'Second Blog Post'],
];
return new ViewModel([
'posts' => $posts,
]);
}
public function detailAction()
{
$id = $this->params()->fromRoute('id', 0);
return new ViewModel([
'postId' => $id,
]);
}
}
- Controllers extend
AbstractActionController. indexAction()shows all posts.detailAction()displays details of a specific post usingid.
β Creating Views
// module/Blog/view/blog/post/index.phtml
<h2>Blog Posts</h2>
<ul>
<?php foreach ($this->posts as $post): ?>
<li>
<a href="/blog/detail/<?= $post['id'] ?>">
<?= $this->escapeHtml($post['title']); ?>
</a>
</li>
<?php endforeach; ?>
</ul>
// module/Blog/view/blog/post/detail.phtml
<h2>Blog Post Detail</h2>
<p>You are viewing post with ID: <?= $this->escapeHtml($this->postId); ?></p>
index.phtmllists blog posts.detail.phtmlshows the selected post ID.
β Best Practices
- Keep routes for each module inside its own
module.config.php. - Use
Segmentfor dynamic parameters like:id. - Return
ViewModelobjects to pass data to views. - Keep controllers lightweightβbusiness logic should go in services or models.
β Exercises
- Add a new route
/blog/createmapped toPostController::createAction. - Update
index.phtmlto display a “View Details” link for each post. - Pass post titles into
detail.phtmlinstead of just the ID. - Create another controller
CategoryControllerwith its own routes and views.
Congratulations! π You have completed Chapter 3: Routing & Controllers in Zend Framework 3.
Your Blog module now has functional routes, controllers, and views.
In the next chapter, weβll cover Views & Layouts in detail.
