pop-router¶
The Pop\Router
sub-component is part of the core popphp/popphp component. It serves as the
primary router to the main application object. With it, you can define routes for both web-based
and console-based applications.
Installation¶
Install it directly into your project:
composer require popphp/popphp
Or, include it in your composer.json file:
{
"require": {
"popphp/popphp": "^3.7.2"
}
}
Basic Use¶
The router object facilitates the configuration and matching of the routes to access your application. It supports both HTTP and CLI routing. With it, you can establish valid routes along with any parameters that may be required with them.
HTTP Route Example
$router->addRoute('/hello', function() {
echo 'Hello World';
});
In the above example, a web request of http://localhost/hello
will execute the closure as the controller and echo
Hello World
out to the browser.
CLI Route Example
$router->addRoute('hello', function($name) {
echo 'Hello World';
});
In the above example, a CLI command of ./app hello
will execute the closure as the controller and echo
Hello World
out to the console.
A controller object can be, and usually is, an instance of a class instead of a closure for more control over what happens for each route:
class MyApp\Controller\IndexController extends \Pop\Controller\AbstractController
{
public function index()
{
echo 'Hello World!';
}
}
$router->addRoute('/', [
'controller' => 'MyApp\Controller\IndexController',
'action' => 'index'
]);
In the above example, the request /
is routed to the index()
method in the defined controller class.
Controller Parameters¶
It’s common to require access to various elements and values of your application while within an instance of your controller class. To provide this, the router object allows you to inject parameters into the controller upon instantiation. Let’s assume your controller’s constructor looks like this:
class MyApp\Controller\IndexController extends \Pop\Controller\AbstractController
{
protected $foo;
protected $bar;
public function __construct($foo, $bar)
{
$this->foo = $foo;
$this->bar = $bar;
}
}
You could then inject parameters into the controller’s constructor like this:
$router->addControllerParams(
'MyApp\Controller\IndexController', [
'foo' => $foo,
'bar' => $bar
]
);
If you require parameters to be injected globally to all of your controller classes, then you can
replace the controller name 'MyApp\Controller\IndexController
with *
and they will be injected
into all controllers. You can also define controller parameters within the route configuration as well.
$config = [
'routes' => [
'/products' => [
'controller' => 'MyApp\Controller\ProductsController',
'action' => 'index',
'controllerParams' => [
'baz' => 789
]
]
]
];
$app = new Pop\Application($config);
Dispatch Parameters¶
Defining route dispatch parameters, you can define required (or optional) parameters that are needed for a particular route:
$router->addRoute('/hello/:name', function($name) {
echo 'Hello ' . ucfirst($name);
});
$router->addRoute('hello <name>', function($name) {
echo 'Hello ' . ucfirst($name);
});
The HTTP request of http://localhost/hello/pop
and the CLI command of ./app hello pop
will each
echo out Hello Pop
to the browser and console, respectively.
Optional Dispatch Parameters
Consider the following controller class and method:
class MyApp\Controller\IndexController extends \Pop\Controller\AbstractController
{
public function hello($name = null)
{
if (null === $name) {
echo 'Hello World!';
} else {
echo 'Hello ' . ucfirst($name);
}
}
}
Then add the following routes for HTTP and CLI:
HTTP:
$router->addRoute('/hello[/:name]', [
'controller' => 'MyApp\Controller\IndexController',
'action' => 'hello'
]);
CLI:
$router->addRoute('hello [<name>]', [
'controller' => 'MyApp\Controller\IndexController',
'action' => 'hello'
]);
In the above example, the parameter $name
is an optional dispatch parameter and the hello()
method performs differently depending on whether or not the parameter value it present.
Dynamic Routing¶
Dynamic routing is also supported. You can define routes as outlined in the examples below and they will be dynamically mapped and routed to the correct controller and method. Let’s assume your application has the following controller class:
class MyApp\Controller\UsersController extends \Pop\Controller\AbstractController
{
public function index()
{
// Show a list of users
}
public function edit($id = null)
{
// Edit the user with the ID# of $id
}
}
You could define a dynamic route for HTTP like this:
$router->addRoute('/:controller/:action[/:param]', [
'prefix' => 'MyApp\Controller\\'
]);
and routes such as these would be valid:
http://localhost/users
http://localhost/users/edit/1001
For CLI, you can define a dynamic route like this:
$router->addRoute('<controller> <action> [<param>]', [
'prefix' => 'MyApp\Controller\\'
]);
and routes such as these would be valid:
./app users
./app users edit 1001
Named Routes¶
Named routes are supported either through the API or through the routes configuration. The benefit of named routes is that it gives a simple name to call up and reference the route when needed.
Via the API
$router = new Pop\Router\Router();
$router->addRoute('/home', function() {
echo 'Home!' . PHP_EOL;
})->name('home');
$router->addRoute('/hello/:name', function($name) {
echo 'Hello, ' . $name . '!' . PHP_EOL;
})->name('hello');
Via Route Configuration
$app = new Application([
'routes' => [
'/home' => [
'controller' => function () {
echo 'Home!' . PHP_EOL;
},
'name' => 'home'
],
'/hello/:name' => [
'controller' => function ($name) {
echo 'Hello, ' . $name . '!' . PHP_EOL;
},
'name' => 'hello'
]
]
]);
URL Generation¶
Using the named routed feature described above, you can generate URLs as needed by calling on the router
and passing an array or object down with any of the dispatch parameters. The simple way to do this is with
the static Pop\Route\Route
class, which can store the application’s current router.
Consider the following named route:
$router->addRoute('/hello/:name', function($name) {
echo 'Hello, ' . $name . '!' . PHP_EOL;
})->name('hello');
Below is an example of how to generate the appropriate URLs for a data set that would utilize that route:
foreach ($names as $name):
echo '<a href="' . Route::url('hello', $name) . '">' . $name->name . '</a><br />' . PHP_EOL;
endforeach;
<a href="/hello/nick">nick</a><br />
<a href="/hello/jim">jim</a><br />
<a href="/hello/world">world</a><br />
Routing Syntax¶
The tables below outline the accepted routing syntax for the route matching:
HTTP¶
Web Route | What’s Expected |
---|---|
/foo/:bar/:baz | The 2 params are required |
/foo/:bar[/:baz] | First param required, last one is optional |
/foo/:bar/:baz* | One required param, one required param that is a collection (array) |
/foo/:bar[/:baz*] | One required param, one optional param that is a collection (array) |
CLI¶
CLI Route | What’s Expected |
---|---|
foo bar | Two commands are required |
foo bar|baz | Two commands are required, the 2nd can accept 2 values |
foo [bar|baz] | The second command is optional and can accept 2 values |
foo -o1 [-o2] | First option required, 2nd option is optional |
foo –option1|-o1 [–option2|-o2] | 1st option required, 2nd optional; long & short supported for both |
foo <name> [<email>] | First param required, 2nd param optional |
foo –name= [–email=] | First value param required, 2nd value param optional |