Controllers
Introduction
Every defined route requires a callable
to invoke when dispatched, something that could be described as a controller in MVC. By default, Route only imposes that the callable is defined with a specific signature, it is given a request object as the first argument, an associative array of wildcard route arguments as the second argument, and expects a response object to be returned. Read more about this in HTTP.
This behaviour can be changed by creating/using a different strategy, read more about strategies here.
Defining Controllers
Defining what controller is invoked when a route is matched is as easy as padding a callable as the the third argument of the map
method or the second argument of the proxy methods for different request verbs, get
, post
etc.
<?php declare(strict_types=1);
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
$router = new League\Route\Router;
$router->map('GET', '/route', function (ServerRequestInterface $request): ResponseInterface {
// ...
});
$router->get('/another-route', function (ServerRequestInterface $request): ResponseInterface {
// ...
});
Types of Controllers
As mentioned above, Route will dispatch any callable
when a route is matched.
For performance reasons, Route also allows you to define controllers as a type of proxy, there are two of these proxies that will allow you to define strings and the actually callable will be built when Route dispatches it.
Closure
A controller can be defined as a simple \Closure
anonymous function.
<?php declare(strict_types=1);
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
$router = new League\Route\Router;
$router->map('GET', '/', function (ServerRequestInterface $request): ResponseInterface {
// ...
});
Lazy Loaded Class Method (Proxy)
You can define a class method as a controller where the callable is to be lazy loaded when it is dispatched by defining a string and separating the class name and method name like so ClassName::methodName
.
<?php declare(strict_types=1);
namespace Acme;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class SomeController
{
/**
* Controller.
*
* @param \Psr\Http\Message\ServerRequestInterface $request
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function someMethod(ServerRequestInterface $request): ResponseInterface
{
// ...
}
}
<?php declare(strict_types=1);
$router = new League\Route\Router;
$router->map('GET', '/', 'Acme\SomeController::someMethod');
Lazy Loaded Class Implementing __invoke
(Proxy)
You can define the name of a class that implements the magic __invoke
method and the object will not be instantiated until it is dispatched.
<?php declare(strict_types=1);
namespace Acme;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class SomeController
{
/**
* Controller.
*
* @param \Psr\Http\Message\ServerRequestInterface $request
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke(ServerRequestInterface $request): ResponseInterface
{
// ...
}
}
<?php declare(strict_types=1);
$router = new League\Route\Router;
$router->map('GET', '/', Acme\SomeController::class);
Lazy Loaded Array Based Callable (Proxy)
A controller can be defined as an array based callable where the class element will not be instantiated until it is dispatched.
<?php declare(strict_types=1);
namespace Acme;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class SomeController
{
/**
* Controller.
*
* @param \Psr\Http\Message\ServerRequestInterface $request
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function someMethod(ServerRequestInterface $request): ResponseInterface
{
// ...
}
}
<?php declare(strict_types=1);
$router = new League\Route\Router;
$router->map('GET', '/', [Acme\SomeController::class, 'someMethod']);
Object Implementing __invoke
<?php declare(strict_types=1);
namespace Acme;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class SomeController
{
/**
* Controller.
*
* @param \Psr\Http\Message\ServerRequestInterface $request
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke(ServerRequestInterface $request): ResponseInterface
{
// ...
}
}
<?php declare(strict_types=1);
$router = new League\Route\Router;
$router->map('GET', '/', new Acme\SomeController);
Array Based Callable
<?php declare(strict_types=1);
namespace Acme;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class SomeController
{
/**
* Controller.
*
* @param \Psr\Http\Message\ServerRequestInterface $request
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function someMethod(ServerRequestInterface $request): ResponseInterface
{
// ...
}
}
<?php declare(strict_types=1);
$router = new League\Route\Router;
$router->map('GET', '/', [new Acme\SomeController, 'someMethod']);
Named Function
<?php declare(strict_types=1);
namespace Acme;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
* Controller.
*
* @param \Psr\Http\Message\ServerRequestInterface $request
*
* @return \Psr\Http\Message\ResponseInterface
*/
function controller(ServerRequestInterface $request): ResponseInterface
{
// ...
}
<?php declare(strict_types=1);
$router = new League\Route\Router;
$router->map('GET', '/', 'Acme\controller');
Dependency Injection
Where Route is instantiating the objects for your defined controller, a dependency injection container can be used to resolve those objects. Read more on dependency injection here.