PHP Route Library: Route requests to registered callback functions

Recommend this page to a friend!
  Info   View files View files (37)   DownloadInstall with Composer Download .zip   Reputation   Support forum (1)   Blog    
Last Updated Ratings Unique User Downloads Download Rankings
2021-01-28 (1 month ago) RSS 2.0 feedStarStarStar 46%Total: 205 All time: 8,277 This week: 377Up
Version License PHP version Categories
route 1.0.24Custom (specified...5HTTP, PHP 5
Collaborate with this project Author

Route - github.com

Description

This package can route requests to registered callback functions.

It can register the URI patterns of different types if requests and calls given callback functions.

Different callback functions may be registered to handle each URI pattern.

The patterns may have parameter markers that are passed to the callback functions are parameters.

Picture of Mahmoud Elnezamy
Name: Mahmoud Elnezamy <contact>
Classes: 1 package by
Country: Egypt Egypt

Details

Route v2.0

Route - Fast, flexible routing for PHP, enabling you to quickly and easily build RESTful web applications.

Installation

$ composer require nezamy/route

Or if you looking for ready template for using this route Go to https://github.com/nezamy/just

Route requires PHP 7.4.0 or newer.

Changes list

  • Rewrite route based on php 7.4
  • Support Swoole extensions
  • Support locales to build multi languages website
  • Added Auth, Basic, Digest
  • Availability to customize route parser and handler
  • Smart dependency injection and service container

Usage

Only if using composer create index.php in root.

Create an index.php file with the following contents:

<?php declare(strict_types=1);

define('DS', DIRECTORY_SEPARATOR);
define('BASE_PATH', __DIR__ . DS);
//Show errors
//===================================
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
//===================================
require BASE_PATH.'vendor/autoload.php';
$request = new Just\Http\GlobalRequest;
$response = new Just\Http\Response;
$route = new Just\Routing\Router($request, $response);
// let store them to container, to use them as a singleton
container()->set(Just\Http\Request::class, $request);
container()->set(Just\Http\Response::class, $response);
container()->set(Just\Routing\Router::class, $route);

try {
    include 'app/routes.php';
    $output = $route->run();

    foreach ($output->headers->all() as $k => $v) {
        header("$k: $v");
    }
    http_response_code($output->statusCode());
    if ($output->hasRedirect()) {
        list($url, $code) = $output->getRedirect();
        header("Location: $url", true, $code);
    }

} catch (\Error $e) {
    pre($e, 'Error', 6);
} catch (\Exception $e) {
    pre($e, 'Exception', 6);
}

echo response()->body();

app/routes.php

<?php
use Just\Route;

Route::get('/', function (){
    return 'Welcome to the home page';
});

// Maybe you want to customize 404 page
Route::setNotfound(function (){
    return 'Page Not found';
});

Use with Swoole

<?php
declare(strict_types=1);

use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;

use Just\Routing\Router;

ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);

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

$http = new Server("0.0.0.0", 9501);
$http->set([
    'document_root' => '/var/www/public',
    'enable_static_handler' => true,
]);
$http->on("request", function (Request $request, Response $response) {

    $request = new Just\Http\Request(
       $request->header ?? [],
       $request->server ?? [],
       $request->cookie ?? [],
       $request->get ?? [],
       $request->post ?? [],
       $request->files ?? [],
       $request->tmpfiles ?? []
    );
    $response = new Just\Http\Response;
    $route = new Just\Routing\Router($request, $response);
	container()->set(Just\Http\Request::class, $request);
	container()->set(Just\Http\Response::class, $response);
	container()->set(Router::class, $route);
    try {
        include __DIR__ .'/app/routes.php';
        $output = $route->run();
        foreach ($output->headers->all() as $k => $v) {
            $response->header($k, $v);
        }

        $response->setStatusCode($output->statusCode());

        if ($output->hasRedirect()) {
            list($url, $code) = $output->getRedirect();
            $response->redirect($url, $code);
        }
    } catch (\Error $e) {
        pre($e, 'Error', 6);
    } catch (\Exception $e) {
        pre($e, 'Exception', 6);
    }
    $response->end(response()->body(true));
});
$http->start();

How it works

Routing is done by matching a URL pattern with a callback function.

app/routes.php

Route::any('/', function() {
    return 'Hello World';
});

Route::post('/contact-us', function(\Just\Http\Request $req) {
    pre($req->body, 'Request');
});

The callback can be any object that is callable. So you can use a regular function:

function pages() {
    return 'Page Content';
}
Route::get('/', 'pages');

Or a class method:

class home
{
    public function pages() {
        return 'Home page Content';
    }
}
Route::get('/', [home::class, 'pages']);
// OR
Route::get('/', 'home@pages');

Method Routing

Route::any('/', function() {});
Route::get('/', function() {});
Route::post('/', function() {});
Route::put('/', function() {});
Route::patch('/', function() {});
Route::option('/', function() {});
Route::delete('/', function() {});

Parameters

// This example will match any page name
Route::get('/{page}', function($page) {
    return "you are in $page";
});

Route::get('/post/{id}', function($id) {
    // Will match anything like post/hello or post/5 ...
    // But not match /post/5/title
    return "post id $id";
});

// more than parameters
Route::get('/post/{id}/{title}', function($id, $title) {
    return "post id $id and title $title";
});

// you can get parameter in any order
Route::get('/post/{id}/{title}', function($title, $id) {
    return "post id $id and title $title";
});

For ?unlimited? optional parameters, you can do this:

// This example will match anything after blog/ - unlimited arguments
Route::get('/blog/{any}:*', function($any) {
    pre($any);
});

Regular Expressions

You can validate the args by regular expressions.

// Validate args by regular expressions uses :(your pattern here)
Route::get('/{username}:([0-9a-z_.-]+)/post/{id}:([0-9]+)',
function($username, $id) {
    return "author $username post id $id";
});

// You can add named regex pattern in routes
Route::addPlaceholders([
    'username' => '([0-9a-z_.-]+)',
    'id' => '([0-9]+)'
]);

// Now you can use named regex
Route::get('/{username}:username/post/{id}:id', function($username, $id) {
    return "author $username post id $id";
});
//if the parameter name match the placeholder name just ignore placeholder and route will deduct that
Route::get('/{username}/post/{id}', function($username, $id) {
    return "author $username post id $id";
});

Some named regex patterns already registered in routes

[
    'int'               => '/([0-9]+)',
    'multiInt'          => '/([0-9,]+)',
    'title'             => '/([a-z_-]+)',
    'key'               => '/([a-z0-9_]+)',
    'multiKey'          => '/([a-z0-9_,]+)',
    'isoCode2'          => '/([a-z]{2})',
    'isoCode3'          => '/([a-z]{3})',
    'multiIsoCode2'     => '/([a-z,]{2,})',
    'multiIsoCode3'     => '/([a-z,]{3,})'
];

Optional parameters

You can specify named parameters that are optional for matching by adding (?)

Route::get('/post/{title}?:title/{date}?',
function($title, $date) {
    $content = '';
    if ($title) {
        $content = "<h1>$title</h1>";
    }else{
        $content =  "<h1>Posts List</h1>";
    }

    if ($date) {
        $content .= "<small>Published $date</small>";
    }
    return $content;

});

Groups

Route::group('/admin', function()
{
    // /admin/
    Route::get('/', function() {});
    // /admin/settings
    Route::get('/settings', function() {});
    // nested group
    Route::group('/users', function()
    {
        // /admin/users
        Route::get('/', function() {});
        // /admin/users/add
        Route::get('/add', function() {});
    });
    // Anything else
    Route::any('/{any}:*', function($any) {
        pre("Page ( $any ) Not Found", 6);
    });
});

Groups with parameters

Route::group('/{module}', function($lang)
{
    Route::post('/create', function() {});
    Route::put('/update', function() {});
});

Locales

// the first language is the default i.e. ar
// when you hit the site http://localhost on the first time will redirect to  http://localhost/ar
Route::locale(['ar','en'], function(){
    // will be /ar/
    Route::get('/', function($locale){
        //get current language
        pre($locale);
    });
    // /ar/contact
    Route::get('/contact', function() {});

    Route::group('/blog', function() {
        // /ar/blog/
        Route::get('/', function() {});
    });
});
// Also you can write locales like that or whatever you want
Route::locale(['ar-eg','en-us'], function(){
    // will be /ar/
    Route::get('/', function($locale){
        //get current language
        list($lang, $country) = explode('-', $locale, 2);
        pre("Lang is $lang, Country is $country");
    });
});

Auth

Basic

$auth = new \Just\Http\Auth\Basic(['users' => [
    'user1' => '123456',
    'user2' => '987654'
]]);
Route::auth($auth, function (){
    Route::get('/secret', function(\Just\Http\Request $req){
        pre("Hello {$req->user()->get('username')}, this is a secret page");
    });
});

Digest

$auth = new \Just\Http\Auth\Digest(['users' => [
    'user1' => '123456',
    'user2' => '987654'
]]);
Route::auth($auth, function (){
    Route::get('/secret', function(\Just\Http\Request $req){
        pre("Hello {$req->user()->get('username')}, this is a secret page");
    });
});

Middleware

Global

Route::use(function (\Just\Http\Request $req, $next){
    //validate something the call next to continue or return whatever if you want break 
    if($req->isMobile()){
        return 'Please open from a desktop';
    }
    
    return $next();
}, function ($next){
    // another middleware
    $next();
});

// After 
Route::use(function ($next){
    $response =  $next();
    // make some action
    return $response;
});

Middleware on groups

// if open from mobile device
Route::middleware(fn(\Just\Http\Request $req, $next) => !$req->isMobile() ? '' : $next())
    ->group('/mobile-only', function (){
        Route::get('/', function(\Just\Http\Request $req){
            pre($req->browser());
        });
    });

If you make the middleware as a class, you can pass the class with namespace. the class should be had a handle method.

class MobileOnly{
    public function handle(\Just\Http\Request $req, $next){
        return !$req->isMobile() ? '' : $next();
    }
}
Route::middleware(MobileOnly::class)
    ->group('/',function (){
        Route::get('/', function(\Just\Http\Request $req){
            pre($req->browser());
        });
    });

Middleware on route

Route::get('/', function(\Just\Http\Request $req){
    pre($req->browser());
})->middleware(MobileOnly::class);

Dependency injection

To learn about Dependency injection and service container please visit this link

Handle and Parser customization

Example of CustomRouteHandler

class CustomRouteHandler implements Just\Routing\RouteHandlerInterface
{
    public function call(callable $handler, array $args = [])
    {
        return call_user_func_array($handler, $args);
    }

    public function parse($handler): callable
    {
        if (is_string($handler) && ! function_exists($handler)) {
            $handler = explode('@', $handler, 2);
        }
        return $handler;
    }
}
\Just\Route::setHandler(new CustomRouteHandler);

class CustomRouteParser implements RouteParserInterface
{
    public function parse(string $uri): array
    {
        $matchedParameter = [];
        $matchedPattern = [];
        $result = [];
        // parse uri here and return array of 3 elements
        // /{page}
        // /{page}?

        return ['parameters' => $matchedParameter, 'patterns' => $matchedPattern, 'result' => $result];
    }
}
\Just\Route::setParser(new CustomRouteParser);
  Files folder image Files  
File Role Description
Files folder imagesrc (2 files, 5 directories)
Files folder imagetests (5 files)
Accessible without login Plain text file .php_cs Example Example script
Accessible without login Plain text file composer.json Data Auxiliary data
Accessible without login Plain text file LICENSE Lic. License text
Accessible without login Plain text file phpunit.xml Data Auxiliary data
Accessible without login Plain text file README.md Doc. Documantion

  Files folder image Files  /  src  
File Role Description
Files folder imageDataType (1 file)
Files folder imageHttp (6 files, 1 directory)
Files folder imagePrototype (7 files)
Files folder imageRouting (6 files)
Files folder imageSupport (2 files)
  Plain text file functions.php Class Class source
  Plain text file Route.php Class Class source

  Files folder image Files  /  src  /  DataType  
File Role Description
  Plain text file Uri.php Class Class source

  Files folder image Files  /  src  /  Http  
File Role Description
Files folder imageAuth (3 files)
  Plain text file Auth.php Class Class source
  Plain text file GlobalRequest.php Class Class source
  Plain text file Middleware.php Class Class source
  Plain text file Request.php Class Class source
  Plain text file Response.php Class Class source
  Plain text file Session.php Class Class source

  Files folder image Files  /  src  /  Http  /  Auth  
File Role Description
  Plain text file AuthInterface.php Class Class source
  Plain text file Basic.php Class Class source
  Plain text file Digest.php Class Class source

  Files folder image Files  /  src  /  Prototype  
File Role Description
  Plain text file ArrayPrototype.php Class Class source
  Plain text file ConvertObject.php Class Class source
  Plain text file Getter.php Class Class source
  Plain text file GetterObject.php Class Class source
  Plain text file ObjectStore.php Class Class source
  Plain text file Setter.php Class Class source
  Plain text file StringPrototype.php Class Class source

  Files folder image Files  /  src  /  Routing  
File Role Description
  Plain text file Route.php Class Class source
  Plain text file RouteHandler.php Class Class source
  Plain text file RouteHandlerInterface.php Class Class source
  Plain text file RouteParser.php Class Class source
  Plain text file RouteParserInterface.php Class Class source
  Plain text file Router.php Class Class source

  Files folder image Files  /  src  /  Support  
File Role Description
  Plain text file ArrayTrait.php Class Class source
  Plain text file Regex.php Class Class source

  Files folder image Files  /  tests  
File Role Description
  Plain text file AuthTest.php Class Class source
  Accessible without login Plain text file bootstrap.php Aux. Auxiliary script
  Plain text file DummyRequest.php Class Class source
  Plain text file RouteParserTest.php Class Class source
  Plain text file RouteTest.php Class Class source

 Version Control Unique User Downloads Download Rankings  
 100%
Total:205
This week:0
All time:8,277
This week:377Up
User Ratings User Comments (2)
 All time
Utility:66%StarStarStarStar
Consistency:58%StarStarStar
Documentation:-
Examples:75%StarStarStarStar
Tests:-
Videos:-
Overall:46%StarStarStar
Rank:2636
  

For more information send a message to info at phpclasses dot org.