• Stars
    star
    267
  • Rank 153,227 (Top 4 %)
  • Language
    PHP
  • Created over 4 years ago
  • Updated about 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Small and fast router

Routing

Latest Stable Version Open Collective Build Status Scrutinizer Code Quality codecov Twitter

Intro

Mezon Framework provides simple routing class for your needs. It is already used in Web Application, Service, CRUD Service.

Contributors

Mezon becomes better because of the contributors. Thank them too.

Once again thank you people for your contributions.

Use this link if you also want to support our project.


Jaume

Lolix

Jamie Smith

FAQ

Use this service for asking questions.

Installation

Just print in console

composer require mezon/router

And that's all.

Reasons to use

The mezon/router is

  • 25 times faster than klein/klein router
  • 7 to 15 times faster than Symfony router
  • 30 to 50 times faster than Laravel router
  • 1.5 times faster than nikic/fast-route

More benchmarks can be found here.

Learn more

More information can be found here:

Twitter

dev.to

What is "First case" and "Second case"?

  1. First case - http server accepts request, launches php script, wich handles this request, and then all script data uploads from memory. All following requests are processed in the same way. In this case very critical to launch script as soon as possible and we do not have time for long pre-compilations and preparations. Because all of it will be lost after the script will finish working.

  2. Second case - php script is launching, initiating all internal components (and router is one of them) and then starting processing requests. This case can be organized via for example react-php. It differs from the previous case because we can spend reasonable time to pre-compile routes for faster.

In this table you can see requests per second. The bigger numbers mean better.

results

mezon and klein comparison

mezon and symfony comparison

mezon and laravel comparison

mezon and fast-route comparison

mezon and yii2 router comparison

I'll be very glad if you'll press "STAR" button

Simple routes

Router allows you to map URLs on your php code and call when ever it needs to be called.

Router supports simple routes like in the example above - example.com/contacts/

Each Application object implicitly creates routes for its action[action-name] methods, where action-name will be stored as a route. Here is small (as usual) example:

class MySite
{
    /**
     * Main page
     */
    public function actionIndex()
    {
        return 'This is the main page of our simple site';
    }

    /**
     * FAQ page
     */
    public function actionFaq()
    {
        return 'This is the "FAQ" page';
    }

    /**
     * Contacts page
     */
    public function actionContacts()
    {
        return 'This is the "Contacts" page';
    }

    /**
     * Some custom action handler
     */
    public function someOtherPage()
    {
        return 'Some other page of our site';
    }
    
    /**
     * Some static method
     */
    public static function someStaticMethod()
    {
        return 'Result of static method';
    }
}

And this code

$router = new \Mezon\Router\Router();
$router->fetchActions($mySite = new MySite());

will create router object and loads information about its actions and create routes. Strictly it will create two routes, because the class MySite has only two methods wich start with action[Suffix]. Method someOtherPage will not be converted into route automatically. By default this method will create routes wich handle both POST and GET request methods.

Then just call to run callback by URL:

$router->callRoute('/index/');

There is a way to specify request methods for each action:

$router->fetchActions($mySite = new MySite(), [
	'Index' => 'GET',
	'Contacts' => 'POST',
	'Faq' => ['GET', 'POST'],
]);

You can manually specify callbacks for every URL in your application:

$router->addRoute('/some-any-other-route/', [$mySite, 'someOtherPage']);

And you also can use static methods:

$router->addRoute('/static-route/', ['MySite', 'someStaticMethod']);
// or in this way
$router->addRoute('/static-route/', 'MySite::someStaticMethod');

We just need to create it explicitly.

We can also use simple functions for route creation:

function sitemap()
{
    return 'Some fake sitemap';
}

$router->addRoute('/sitemap/', 'sitemap');

And you can find callback without launching it:

$router->addRoute('/static-route/', 'MySite::someStaticMethod');
$callback = $router->getCallback('/static-route/');
var_dump($callback());

Supported request methods

Mezon Router supports:

  • GET
  • POST
  • PUT
  • DELETE
  • OPTION
  • PATCH

To get the list of these methods you can use method getListOfSupportedRequestMethods:

$router = new \Mezon\Router\Router();
var_dump($router->getListOfSupportedRequestMethods());

One handler for all routes

You can specify one processor for all routes like this:

$router->addRoute('/*/', function(){});

Note that routing search will stops if the * handler will be found. For example:

$router->addRoute('/*/', function(){});
$router->addRoute('/index/', function(){});

In this example route /index/ will never be reached. All request will be passed to the * handler. But in this example:

$router->addRoute('/contacts/', function(){});
$router->addRoute('/*/', function(){});
$router->addRoute('/index/', function(){});

route /contacts/ will be processed by its own handler, and all other routes (even /index/) will be processed by the * handler.

Route variables

And now a little bit more complex routes:

$router->addRoute('/catalogue/[i:cat_id]/', function($route, $variables){});
$router->addRoute('/catalogue/[a:cat_name]/', function($route, $variables){});

Here:

  • i - any integer number
  • a - any [a-z0-9A-Z_/-.@]+ string
  • il - comma separated list of integer ids
  • s - any string

Parameter name must consist of the following chars: [a-zA-Z0-9_-]

All this variables are passed as second function parameter wich is named in the example above - $variales. All variables are passed as an associative array.

Request types and first steps to the REST API

You can bind handlers to different request types as shown bellow:

$router->addRoute('/contacts/', function(){}, 'POST'); // this handler will be called for POST requests
$router->addRoute('/contacts/', function(){}, 'GET');  // this handler will be called for GET requests
$router->addRoute('/contacts/', function(){}, 'PUT');  // this handler will be called for PUT requests
$router->addRoute('/contacts/', function(){}, 'DELETE');  // this handler will be called for DELETE requests
$router->addRoute('/contacts/', function(){}, 'OPTION');  // this handler will be called for OPTION requests
$router->addRoute('/contacts/', function(){}, 'PATCH');  // this handler will be called for PATCH requests

Reverse routes

You can reverse routes and compile URLs by route's name. For example:

$router = new \Mezon\Router\Router();
$router->addRoute('/some-route/[i:id]', function(){}, 'GET', 'name of the route');
// will output /some-route/123
var_dump($router->reverse('name of the route', ['id' => 123]));

Routes caching

Since version 1.1.0 you can cache routes on disk and read them from this cache.

To dump cache on disk use:

$router->dumpOnDisk('./cache/cache.php');

And after that you can load routes:

$router->loadFromDisk('./cache/cache.php');

But these methods have limitations - they can not dump and load closures because of obvious reasons.

You can also warm cache without dumping:

$router->warmCache();

Middleware and parameters modification

Types of middlewares that you can add which will be called before the route handler will be executed. This middleware can transform common parameters $route and $parameters into something different.

  • Multiple global middlewares that will be called in order of attachment.
  • Multiple route specific middlewares that will be called in order of attachment.

Order of execution of the middlewares

  1. Global middlewares $router->addRoute('*', ...).
  2. Before calling route callback $router->addRoute('/example', ...) all those matching the route will be executed.

Let's look at a simple example:

$router = new Router();
$router->addRoute('/user/[i:id]', function(string $route, array $parameters){
    $userModel = new UserModel();
    $userObject = $userModel->getUserById($parameters['id']);

    // use $userObject for any purpose you need
});

Now let's watch an example with all the possibilities.

$router = new Router();

// First step. We have an API that talks JSON, convert the body
$router->registerMiddleware('*', function (string $route, array $parameters){
    $request = Request::createFromGlobals();
    
    $parameters['_request'] = $request;
    $parameters['_body'] = json_decode($request->getContent(), true);

    return $parameters;    
});

// Second step. Ensure that we are logged in when we are in the private area
$router->registerMiddleware('*', function (string $route, array $parameters){
    // Is not a private area
    if (mb_strpos($route, '/user') !== 0 || empty($parameters['user_id'])) {
        return $parameters;
    }

    $token = $parameters['_request']->headers->get('oauth_token');

    $auth = new SomeAuth();
    $auth->validateTokenOrFail(
        $token,
        $parameters['user_id']
    );

    // We don't need to return nothing
});

// Last step. Now we will modify the parameters so the handler can work with them
$router->registerMiddleware('/user/[i:user_id]', function(string $route, array $parameters){
    $userModel = new UserModel();
    
    return $userModel->getUserById(
        $parameters['user_id']
    );
});

// Final destination. We have ended the middlewares, now we can work with the processed data
$router->addRoute('/user/[i:user_id]', function (UserObject $userObject){
    // Do everything
});

PSR-7 routes processing

Originally Mezon Router was not designed to be PSR-7 compatible. But one of the latest features have made it possible. You can use middleware for this purpose. For example:

$router = new Router();
$router->addRoute('/user/[i:id]', function(\Nyholm\Psr7\Request $request){
    // work here with the request in PSR-7 way

    $psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory();

    $responseBody = $psr17Factory->createStream('Hello world');
    $response = $psr17Factory->createResponse(200)->withBody($responseBody);
    (new \Zend\HttpHandlerRunner\Emitter\SapiEmitter())->emit($response);
});

$router->registerMiddleware('/user/[i:id]', function(string $route, array $parameters){
    $psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory();

    $creator = new \Nyholm\Psr7Server\ServerRequestCreator(
        $psr17Factory, // ServerRequestFactory
        $psr17Factory, // UriFactory
        $psr17Factory, // UploadedFileFactory
        $psr17Factory  // StreamFactory
    );

    return $creator->fromGlobals();
});

The best thing about it - if you don't use PSR-7 in your project, then you don't "pay" for it.

Custom types

You can define your own types for URL parser. Let's try to create date type.

First of all we should create simple class:

class DateRouterType
{

    /**
     * Method returns regexp for searching this entity in the URL
     *
     * @return string regexp for searching
     */
    public static function searchRegExp(): string
    {
        return '(\[date:'.BaseType::PARAMETER_NAME_REGEXP.'\])';
    }
}

Here BaseType::PARAMETER_NAME_REGEXP is a global setting wich tells router that parameter names must consist of:

  • a-z and A-Z letters
  • 0-9
  • and symbols _ and -

Now we need to define one more class method wich will parse date if it will occur:

public static function parserRegExp(): string
{
    // pretty simple regexp
    return '([0-9]{4}-[0-9]{2}-[0-9]{2})';
}

And somewhere in your setup files you need to switch this type on:

$router->addType('date', DateRouterType::class);

Now you can handle routes like this:

/some-url-part/2020-02-02/ending-part/
/posts-for-2020-02-02/

But be careful. For example you will define such routes:

$router->addRoute('/posts-for-[date:posts-date]/', function(UserObject $userObject){
    // some activities here
});

$router->addRoute('/[s:some-url]/', function(UserObject $userObject){
    // some activities here
});

Then the first handler /posts-for-[date:posts-date]/ will be called for the route /posts-for-2020-02-02/.

More Repositories

1

mezon

Mezon is a simple php framework wich will help you to create business applications.
PHP
42
star
2

mezon-pop3-client

Small and simple POP3 client
PHP
8
star
3

mezon-application

Simple class for creating applictions
PHP
8
star
4

mezon-crud-service

CRUD service classes
PHP
7
star
5

mezon-social-network

PHP
6
star
6

mezon-service

PHP
6
star
7

mezon-cli

PHP
5
star
8

mezon-infrastructure-layer

PHP
5
star
9

mezon-conf

Config routine
PHP
5
star
10

mezon-pdocrud

PDO wrapper
PHP
4
star
11

mezon-dns-client

Dns client for services
PHP
4
star
12

mezon-html-template

HTML template class
PHP
4
star
13

mezon-router-benchmark

PHP
4
star
14

mezon-filter

Class for compilation of filters wich can be as URL parameters
PHP
4
star
15

mezon-rest-exception

REST exception class
PHP
3
star
16

mezon-security

Security routine
PHP
3
star
17

mezon-crud-service-collection

Collection of records
PHP
3
star
18

mezon-utils

Different utilities
PHP
3
star
19

mezon-gui

Set of GUI utilities and classes
PHP
3
star
20

mezon-jira-client

PHP
3
star
21

mezon-cache

PHP
3
star
22

mezon-field

PHP
3
star
23

mezon-date-time-utils

PHP
3
star
24

mezon-ajax-application

PHP
3
star
25

mezon-html-report

PHP
3
star
26

mezon-remote-field

PHP
3
star
27

mezon-view

PHP
3
star
28

mezon-functional

Library with functional routines
PHP
3
star
29

mezon-template-engine

Template engine
PHP
3
star
30

mezon-service-model

Class for mezon service models
PHP
3
star
31

mezon-custom-client

Custom service's client
PHP
3
star
32

mezon-service-client

Service client class
PHP
2
star
33

mezon-test-data-manager

PHP
2
star
34

php-2-excel

PHP
2
star
35

mezon-common-application

PHP
2
star
36

mezon-crud-service-client-adapter

Adpater for list builder
PHP
2
star
37

mezon-record-field

PHP
2
star
38

mezon-list-builder-adapter

List builder adapter
PHP
2
star
39

mezon-http-request-params

Class for parameters fetching from the HTTP request
PHP
2
star
40

mezon-variadic-model

PHP
2
star
41

mezon-service-logic

Service's logic class
PHP
2
star
42

mezon-crud-service-client

CRUD service client class
PHP
2
star
43

mezon-singleton

PHP
2
star
44

mezon-crud-service-model

Model with CRUD operations
PHP
2
star
45

mezon-request-params

Request parameters fetcher
PHP
2
star
46

selenium-low-level-tools

PHP
2
star
47

mezon-request

PHP
2
star
48

mezon-security-provider

Security provider for services and controllers
PHP
2
star
49

mezon-service-transport

Base transport class for services and applications
PHP
2
star
50

mezon-gentella

gentella adapter for mezon
PHP
2
star
51

mezon-fields-set

set of fields with types and constraints
PHP
2
star
52

mezon-checkbox-field

PHP
2
star
53

mezon-application-actions

Default actions for application class based on CRUD service
PHP
2
star
54

game

PHP
1
star
55

mezon-template-engine-benchmark

1
star
56

mezon-presenter-to-logic-adapter

1
star
57

builder

Python
1
star
58

mezon-presenter

PHP
1
star
59

mezon-router-benchmark-7x

PHP
1
star
60

mezon-model

PHP
1
star
61

mezon-formal-grammar

PHP
1
star