ignaszak/router

Simple object oriented PHP Router

v2.1.1 2016-05-01 22:40 UTC

This package is not auto-updated.

Last update: 2024-10-25 13:46:04 UTC


README

Build Status Coverage Status

Simple object oriented PHP Router

Installing

The package is available via Composer/Packagist, so just add following lines to your composer.json file:

{
    "require" : {
        "ignaszak/router" : "*"
    }
}

or:

php composer.phar require ignaszak/router

Configuration

The easiest way is to configure mod_rewrite via .htaccess file in site base directory. Example:

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L]

Running Tests

Just run phpunit from the working directory

php phpunit.phar

Usage

Demo

use Ignaszak\Router\Collection\Route;
use Ignaszak\Router\Matcher\Matcher;
use Ignaszak\Router\Host;
use Ignaszak\Router\Response;

include __DIR__ . '/vendor/autoload.php';

// Define routes
$route = Route::start();
$route->add('name', '/test/{test}/{id}/{globlToken}', 'GET|POST')
    ->tokens([
        'test' => '(\w+)',
        'id' => '(\d+)'
    ]);
$route->get('get', '/get/test')->controller('AnyController');
$route->post('post', '/post/{name}')
    ->tokens(['name' => '([a-z]+)'])
    ->defaults(['name' => 'demo'])
    ->attach(function ($name) {
        echo $name;
    });
$route->addTokens(['globalToken' => '([0-9]+)']);

// Match routes
$matcher = new Matcher($route);
$response = new Response($matcher->match(new Host()));
$response->all();

Create routes

Add routes

use Ignaszak\Router\Collection\Route;

include __DIR__ . '/vendor/autoload.php';

$route = Route::start();

// Define name (is not required but if is defined it must be unique for each defined routes),
// pattern and http method (it is possible to combine all http methods e.g.:
// 'GET|POST', not required, if is empty - route match for all methods).
$route->add('name', '/test/(\w+)/', 'GET');

// There are two more add methods:
$route->get(null, '/match/only/get');
$route->post(null, '/match/only/post');

Add tokens

$route->add(null, '/test/{test}/{name}/{id}')->tokens([
    'test' => '(\w+)',
    'name' => '(\w+)',
    'id' => '(\d+)'
]);

Define default values

$route->add(null, '/test/{test}/{name}/{id}')->tokens([
    'name' => '(\w+)'
])->defaults([
    'name' => 'test'
]);

Add controller

$route->add('user', '/user')->controller('UserController');

// Define controller from route
$route->add(null, '/test/{controller}/{action}')
    ->controller('\\Namespace\\{controller}::{action}')
    ->tokens([
        'controller' => '([a-zA-Z]+)',
        'action' => '([a-zA-Z]+)'
    ]);

Add attachment

use Ignaszak\Router\IResponse;

$route->add('attach', '/attach/{name}/(\w+)/{id}/')
    ->tokens([
        'name' => '(\w+)',
        'id' => '(\d+)'
    ])->attach(function (IResponse $response) {
        // IResponse interface - described in 'Get response' section
        print_r($response->all());
    });

Group routes

// Every added route after this method will be in the same group
$route->group('groupName');
// Disable group
$route->group();

Add defined patterns

Router provides some defined regular expressions such as:

  • @base - use to define default route
  • @notfound - not found
  • @digit - digits [0-9]
  • @alpha - alphabetic characters [A-Za-z_-]
  • @alnum - alphanumeric characters [A-Za-z0-9_-]
$route->add('defined', '/regex/@alpha/{id}')->tokens(['id' => '@digit']);

// Add default route
$route->add('default', '/@base')->controller('DefaultController');

// Not found
$route->add('error', '/@notfound')->attach(function () {
    throw new Exception('404 Not Found');
});

Add global tokens and patterns

Global tokens and patterns are avilable for all routes

// Global tokens
$route->addTokens([
    'slug' => '(\w+)',
    'user' => '(\w+)',
    'page' => '(\d+)'
]);
// Define default values for global tokens
$route->addDefaults([
    'slug' => 'test',
    'user' => 'demo',
    'page' => 1
]);

// Create new patterns
$route->addPatterns([
    'day' => '([0-9]{2})',
    'month' => '([0-9]{2})',
    'year' => '([0-9]{4})'
]);
// Example: $route->add(null, '/@year/@month/@day/');

Match routes

use Ignaszak\Router\Collection\Route;
use Ignaszak\Router\Matcher\Matcher;
use Ignaszak\Router\Host;

include __DIR__ . '/autoload.php';

$route = Route::start();
/* Define routes */

// Add defined routes to matcher
$matcher = new Matcher($route);
// Match routes with Host class
$matcher->match(new Host());
// Or define custom request and http method
$matcher->match(null, '/custom/request', 'GET');
Host class
new Host([string $baseQuery]);

Class provides current request and http method. Argument $baseQuery defines folder via site is avilable e.g.: http://localhost/~user/ => $baseQuery = /~user (without trailing slash).

Get response

use Ignaszak\Router\Collection\Route;
use Ignaszak\Router\Matcher\Matcher;
use Ignaszak\Router\Host;
use Ignaszak\Router\Response;

$route = Route::start();
/* Define routes */

$matcher = new Matcher($route);
/* Match routes */

// Get response
$response = new Response($matcher->match(new Host()));

// Get route name
$response->name();
// Get route controller
$response->controller();
// Get route group
$response->group();
// Get matched params in array
$response->all();
// Get param by token
$response->get(string $token [, $default = null]);
// Get tokens array
$response->tokens();
// Returns true if the token is defined
$response->has(string $token);

Reverse Routing

Url can be generated for any defined route with name by using UrlGenerator(IRoute $route [, Host $host]) class.

use Ignaszak\Router\Collection\Route;
use Ignaszak\Router\Matcher\Matcher;
use Ignaszak\Router\Host;
use Ignaszak\Router\Response;
use Ignaszak\Router\UrlGenerator;

$route = Route::start();
/* Define routes */

$host = new Host();

$matcher = new Matcher($route);
$response = new Response($matcher->match($host));

// UrlGenerator
$url = new UrlGenerator($route, $host);
// Example route: $route->get('user', '/user/{user})->tokens(['user' => '@alnum']);
$url->url('user', ['user' => 'UserName']);

UrlGenerator::url(string $name [, array $replacement]) method will return:

  • if Host class is used: http://servername/user/UserName
  • if Host class is not defined: /user/UserName

Load routes from Yaml

Yaml file example

You can define routes, global tokens and patterns. Attachment is not available in yaml file. example.yml:

routes:
    test:
        path: '/test/{controller}/{action}'
        method: GET
        controller: '\Namespace\{controller}::{action}'
        group: groupName
        tokens:
            controller: '@custom'
        defaults:
            controller: HomePageController
    default:
        path: /@base
        controller: DefaultController
    error:
        path: /@notfound
        controller: ErrorController

tokens:
    action: '@alnum'

defaults:
    action: index

patterns:
    custom: ([a-zA-Z]+)

Yaml class

use Ignaszak\Router\Collection\Yaml;
use Ignaszak\Router\Matcher\Matcher;

$yaml = new Yaml();
// Add yaml files
$yaml->add('example.yml');
$yaml->add('anotherExample.yml');

$matcher = new Matcher($yaml);
/* Match routes and get response */

Cache

It is possible to generate cache of routes defined in yaml file or Route class. Cache stores converted routes to regex, so it is no need to read yaml file and convert routes at every request.

use Ignaszak\Router\Collection\Yaml;
use Ignaszak\Router\Collection\Cache;
use Ignaszak\Router\Matcher\Matcher;

$yaml = new Yaml();
$yaml->add('example.yml');

$cache = new Cache($yaml);
$cache->tmpDir = __DIR__; // Define custom tmp dir - optional

$matcher = new Matcher($cache);
/* Match routes and get response */