Skip to content

Creating Controllers

An alternative way of defining request logic in a route is by organizing it by utilizing Controllers. In this article you will learn about basic controllers, resource controllers and restful controllers. As a defined default in Devflow, all custom controllers go into Cms/Http/Controllers directory.

Basic Controller

Here is a simple example of a basic controller with an index method which responds to an incoming request.

<?php

declare(strict_types=1);

namespace Cms\Http\Controllers;

use Codefy\Framework\Http\BaseController;
use Qubus\Http\Session\SessionService;
use Qubus\Routing\Router;
use Qubus\View\Native\Exception\InvalidTemplateNameException;
use Qubus\View\Native\Exception\ViewException;
use Qubus\View\Renderer;

final class HomeController extends BaseController
{
    public function __construct(
        SessionService $sessionService,
        Router $router,
        ?Renderer $view = null
    ) {
        parent::__construct($sessionService, $router, $view);
    }

    /**
     * @throws ViewException
     * @throws InvalidTemplateNameException
     */
    public function index(): ?string
    {
        return $this->view->render('cms::index', ['title' => 'Devflow Site']);
    }
}

Now, we can define a route to the controller's method index with a custom route class:

<?php

declare(strict_types=1);

namespace Cms\Http\Routes;

use Qubus\Routing\Router;

final class MyFrontendRoute
{
    public function handle(Router $router): void
    {
        $router->get('/', 'HomeController@index');
    }
}

When an incoming request matches a route's uri, the index method in the HomeController will be invoked.

Please note that controllers do not have to extend Codefy's BaseController, but doing so gives you access to the native template engine, the router, and the middleware method.

Resource Controller

You can create controllers that automatically handle all the route/CRUD requests. When creating a resource controller, you can implement the resource controller interface: Qubus\Routing\Interfaces\ResourceController, but you don't have to. You can extend the interface to override some of the methods and their parameters or create your own interface based on the specifications of your project/application.

<?php

namespace Qubus\Routing\Interfaces;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

interface ResourceController
{
    /**
     * Display a listing of the resource.
     */
    public function index();

    /**
     * Display the specified resource.
     */
    public function show(int|string $id): ResponseInterface;

    /**
     * Store a newly created resource in storage.
     */
    public function store(RequestInterface $request): ResponseInterface;

    /**
     * Show the form for creating a new resource.
     */
    public function create(): ResponseInterface;

    /**
     * Show the form/view for editing the specified resource.
     */
    public function edit(int|string $id): ResponseInterface;

    /**
     * Update the specified resource in storage.
     */
    public function update(RequestInterface $request): ResponseInterface;

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(int|string $id): ResponseInterface;
}

If you want to use middleware in your resource controller, then your controller should extend the abstract controller class: Codefy\Framework\Http\BaseController.

<?php

declare(strict_types=1);

namespace Cms\Http\Controllers;

use Cms\Http\Middleware\AddHeaderMiddleware;
use Codefy\Framework\Http\BaseController;
use Qubus\Http\Session\SessionService;
use Qubus\Routing\Interfaces\ResourceController;
use Qubus\Routing\Router;
use Qubus\View\Renderer;

class PostController extends BaseController implements ResourceController
{
    public function __construct(
        SessionService $sessionService,
        Router $router,
        ?Renderer $view = null
    ) {
        $this->middleware(AddHeaderMiddleware::class);

        parent::__construct($sessionService, $router, $view);
    }

    public function index(): string
    {
        return 'Index of post controller.';
    }

    ```
}

Register a resourceful route to the controller:

<?php

declare(strict_types=1);

namespace Cms\Http\Routes;

use Qubus\Routing\Router;

final class MyFrontendRoute
{
    public function handle(Router $router): void
    {
        $router->resource('posts', 'PostController');
    }
}

You can register multiple resource controllers by passing in an array in the resource method:

<?php

declare(strict_types=1);

namespace Cms\Http\Routes;

use Qubus\Routing\Router;

final class MyFrontendRoute
{
    public function handle(Router $router): void
    {
        $router->resource([
            'posts' => 'PostController',
            'users' => 'UserController'
        ]);
    }
}

Actions handled by Resource Controller:

Verb Uri Action Route Name
GET /posts index posts.index
GET /posts/create create posts.create
POST /posts/store store posts.store
GET /posts/{posts} show posts.show
GET /posts/{posts}/edit edit posts.edit
PUT/PATCH /posts/{posts} update posts.update
DELETE /posts/{posts} destroy posts.destroy

RESTful Controller

You can conveniently create controllers that will be consumed by an api by using the apiResource method:

<?php

declare(strict_types=1);

namespace Cms\Http\Routes;

use Qubus\Routing\Router;

final class MyFrontendRoute
{
    public function handle(Router $router): void
    {
        $router->apiResource('users', 'UserRestController');
    }
}

You can register several api resources by passing in an array to the apiResources method:

<?php

declare(strict_types=1);

namespace Cms\Http\Routes;

use Qubus\Routing\Router;

final class MyFrontendRoute
{
    public function handle(Router $router): void
    {
        $router->apiResources([
            'posts' => 'PostRestController',
            'users' => 'UserRestController'
        ]);
    }
}

Controller Middleware

A middleware can be defined on your routes or in your controllers:

<?php

declare(strict_types=1);

namespace Cms\Http\Routes;

use Cms\Http\Middleware\AuthMiddleware;
use Qubus\Routing\Router;

final class MyFrontendRoute
{
    public function handle(Router $router): void
    {
        $router->resource('posts', 'PostController')->middleware(AuthMiddleware::class);
    }
}

Alternatively, you can use middleware method in your Controller's constructor:

<?php

declare(strict_types=1);

namespace Cms\Http\Controllers;

use Cms\Http\Middleware\AuthMiddleware;
use Codefy\Framework\Http\BaseController;
use Qubus\Http\Session\SessionService;
use Qubus\Routing\Router;
use Qubus\View\Renderer;

class PostController extends BaseController implements ResourceController
{
    public function __construct(
        SessionService $sessionService,
        Router $router,
        ?Renderer $view = null
    ) {
        $this->middleware(AuthMiddleware::class);

        parent::__construct($sessionService, $router, $view);
    }

    ```
}

This is just a brief introduction to using middleware. Check out CodefyPHP's Middleware docs for more details.