Что такое роутер в php

Встречал «сайты», где весь код упакован в километровую простыню с кучей if/case, внутри которых и обрабатывались те или иные запросы. В целом это плохо по многим причинам, одна из которых — в интерпретатор при каждом запросе вгружается очень много кода, который надо распарсить и пр., и 99% которого не используется принципиально.

Чтобы подобные безобразия пресечь на корню, принято функциональные блоки выносить в отдельные «модули», и подгружать на конкретный запрос только их, в купе с ядром и стандартными библиотеками (что по сути можно назвать «фреймворк»).

Так вот, чтобы ядро могло разрулить на какие запросы какие функциональные блоки (контроллеры) подгружать для обработки этих самых запросов, логика маршрутизации и выносится в роутер.

Для своего движка я сделал предельно простой роутер, который на входе ждет название модуля и его экшена, которому необходимо передать обработку запроса, причем модуль, по сути — это просто папка внутри папки modules, а экшен — это некая папка внутри папки модуля, т.е. modules/[module]/[action]/[action].php, соответственно модуль/экшен добавляется в проект через создание пары папок и файла. Все остальные параметры ЧПУ передаются в экшен в переменной GET.

Таким образом все что делает роутер — генерирует путь, и проверяет, есть ли там соответствующий файл PHP, и если есть — подгружает его и передает ему управление.

Если роутер не получил название экшена и.или модуля, то подставляется default, если по указанному пути файл не обнаружен, то выдается 404. Предельно просто и прозрачно, и всегда наверняка знаешь где и что лежит и как называется и почему.

Подобный подход практикуется в JavaScript фреймворке Ember.JS, под подходом я подразумеваю весьма жесткие соглашения относительно структуры и именования папок, и файлов проектов.

Шаблоны в моих проектах точно так же находятся в строго определенных местах и подключаются экшенами автоматически, если тип их выдачи HTML, иначе генерится JSON, или что-то еще, имеется несколько конвертеров на выходе, подключается тот, который запросил экшен.

Cover image for Building a PHP Framework: Part 8 - Routing

Originally posted on DevelopmentMatt.com

Part 7 got us up to speed on the container that will be used in the Analyze PHP Framework. In this post we’ll cover how routing works in general and specifically within PHP.

How Routing Works

Routing is the process of parsing a URI and determining the appropriate action to take.

For example, consider the following URI:

https://example.com/login

Enter fullscreen mode

Exit fullscreen mode

How does a request like the one above result in a response to the user? Let’s break it down:

  1. The request is received by the application.

  2. The application breaks down the request into its components. Things like: the method (ex: GET), host, path, etc.

  3. The application looks for a defined route that matches this request.

  4. Once found, it takes the defined action and returns a response.

A Laravel Example

For a real-world example, here’s one way the above example could be implemented in Laravel.

Route::get('/login', function() {
    return view('login');
});

Enter fullscreen mode

Exit fullscreen mode

We define a GET route for the /login URI. When that route is requested we return a response – in this case, HTML for the login page.

How Routers Work

There are a number of routers in the PHP ecosystem. They range from the more simplistic to feature-packed behemoths. Although they differ in size and complexity, they generally employ the same fundamental steps: parse the request, match the pattern, run some code, return a response.

The Symfony router (probably the most widely used PHP router) does this.

As does this one.

And this one.

A Very Simple PHP Router

To demonstrate these concepts let’s create a stupid simple, not at all useful, PHP router.

<?php
/**
 * First, let's define our Router object.
 */
class Router
{
    /**
     * The request we're working with.
     *
     * @var string
     */
    public $request;

    /**
     * The $routes array will contain our URI's and callbacks.
     * @var array
     */
    public $routes = [];

    /**
     * For this example, the constructor will be responsible
     * for parsing the request.
     *
     * @param array $request
     */
    public function __construct(array $request)
    {
        /**
         * This is a very (VERY) simple example of parsing
         * the request. We use the $_SERVER superglobal to
         * grab the URI.
         */
        $this->request = basename($request['REQUEST_URI']);
    }

    /**
     * Add a route and callback to our $routes array.
     *
     * @param string   $uri
     * @param Callable $fn
     */
    public function addRoute(string $uri, \Closure $fn) : void
    {
        $this->routes[$uri] = $fn;
    }

    /**
     * Determine is the requested route exists in our
     * routes array.
     *
     * @param  string  $uri
     * @return boolean
     */
    public function hasRoute(string $uri) : bool
    {
        return array_key_exists($uri, $this->routes);
    }

    /**
     * Run the router.
     *
     * @return mixed
     */
    public function run()
    {
        if($this->hasRoute($this->request)) {
            $this->routes[$this->request]->call($this);
        }
    }
}

/**
 * Create a new router instance.
 */
$router = new Router($_SERVER);

/**
 * Add a "hello" route that prints to the screen.
 */
$router->addRoute('hello', function() {
    echo 'Well, hello there!!';
});

/**
 * Run it!
 */
$router->run();

Enter fullscreen mode

Exit fullscreen mode

Run The Code

  1. Save this code locally as index.php.
  2. In your terminal navigate to the directory where you saved the script.
  3. Start the built-in PHP web server: php -S localhost:1234
  4. In your browser go to: http://localhost:1234/hello

Conclusion

I’ve touched on the very basics of routing, shared some routing examples from the PHP world, and built a extremely simple router. On a related note, I’ve started work on the router that will be used in the Analyze PHP framework. To keep up to speed on it, be sure to follow @AnalyzePHP on Twitter.

One last thing, be sure to checkout my newsletter! Each week I’ll send you a great email filled with updates, great links, tips & tricks, and other non-dev randomness. If you’re interested you can sign up by following this link.

When you begin your PHP journey, chances are that you will primarily hard code file paths in the URL to access them.

Let’s say you have a project called platform with the following files.

  • index.php: welcome note
  • courses.php: list of courses
  • authors.php: list of authors
  • aboutus.php: about the platform

How beginners navigate files

Imagine you want to access a list of all authors. What do you do? You type platform.com/authors.php on the URL.

It works, but what if you decide to change the name of the file one day? You’ll have to fix it everywhere you called this link.

Another issue with this way of directly calling files is that you reveal the project’s internal structure to the world, which is unsafe for security purposes.

Lastly, the URL does not look elegant. For example, calling a URL like platform.com/authors is more elegant than platform.com/authors.php.

Let’s see how we can do better.

How professionals navigate files

To do things better, we’ll need to create a routing system, which is a technique that consists of mapping all HTTP requests to a request handler. We will:

  • redirect all HTTP requests to index.php (the router)
  • create a routing system with switch

Redirect all HTTP requests to the router

To redirect all HTTP requests to the router, create a file named .htaccess on the root of the project and redirect all traffic to index.php. This is shown below:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php 

In our .htaccess file, we first activate the Apache server’s runtime rewriting engine. We limit access to physical files with Apache RewriteCond directive. Then, we redirect all upcoming requests to the index.php file.

.htaccess is a configuration file for the Apache server. It has no extension, but starts with a dot (.) for a hidden file.

In case your app/site is not at the root of your server, or if you don’t have a virtual host, you’ll need to create your .htaccess. This is shown below:

RewriteEngine On
RewriteBase /<folder>/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /folder/index.php [L]

Note: Replace <folder> with the name of the folder containing your site.

Create a routing system with switch

Our routing system will work as follows:

  • get the user requested path with $_SERVER super global variable
  • require the corresponding page

Code

Add the code below after an index.php file is created.

Роутер PHP – это мощный инструмент, который помогает упростить процесс обработки запросов веб-приложения. Он позволяет разработчикам определить, какие действия должны выполняться в зависимости от запрашиваемого URL. Таким образом, роутер PHP осуществляет связь между URL и соответствующим кодом, выполняющим нужные действия.

Основное преимущество использования роутера PHP заключается в том, что он позволяет создавать гибкие маршруты для веб-приложения. Вы можете определить структуру URL, которая соответствует вашим потребностям и обеспечивает удобную навигацию для пользователей. Кроме того, роутер PHP позволяет разделить логику приложения на отдельные контроллеры и методы, что облегчает разработку и поддержку кода.

Пользоваться роутером PHP довольно просто. Вам необходимо создать файл, в котором определены все маршруты вашего веб-приложения. Затем, при обработке каждого запроса, роутер PHP смотрит на URL и определяет, какой контроллер и метод должны быть вызваны. Это позволяет обрабатывать запросы эффективно и доставлять нужные данные пользователю.

Содержание

  1. Что такое роутер PHP?
  2. Определение и принцип работы
  3. Зачем нужен роутер PHP?
  4. Как пользоваться роутером PHP?
  5. Преимущества и недостатки

Что такое роутер PHP?

Роутер PHP позволяет легко определить правила маршрутизации, которые связывают URL-адресы с определенными действиями или функциями в вашем коде PHP. Он позволяет разработчикам создавать дружелюбные URL-ы, которые легко запоминать и использовать для навигации по веб-приложению. Роутеры также позволяют обрабатывать динамические URL-адреса, включая параметры и переменные в URL.

Когда пользователь вводит URL-адрес веб-приложения, роутер PHP проверяет это URL-адрес и ищет соответствующее правило маршрутизации. Если соответствие найдено, роутер запускает соответствующий контроллер, который обрабатывает запрос и возвращает нужную информацию или выводит нужное представление.

Для использования роутера PHP обычно требуется настройка в файлах .htaccess или конфигурации веб-сервера, чтобы перенаправлять все запросы к одной точке входа (например, index.php), где роутер будет обрабатывать запросы и вызывать соответствующие действия или контроллеры.

Использование роутера PHP помогает создать чистую и организованную структуру кода, а также упрощает масштабирование и обслуживание вашего веб-приложения.

Определение и принцип работы

Основной принцип работы роутера PHP заключается в сопоставлении URL-адресов с определенными обработчиками, которые выполняют соответствующие действия. Каждое действие обычно представлено веб-страницей или функцией, которая работает с данными и возвращает результат. Роутер обеспечивает связь между URL-адресами и обработчиками, позволяя вызывать нужный обработчик для каждого запроса.

При работе с роутером PHP необходимо определить набор правил маршрутизации, которые будут указывать, какие URL-адреса должны быть направлены на какие обработчики. Эти правила обычно задаются в файле конфигурации или в коде приложения. При получении HTTP-запроса, роутер проверяет URL-адрес и сопоставляет его с правилами, чтобы определить, какой обработчик должен быть вызван.

Роутер PHP также может обрабатывать различные типы запросов, такие как GET, POST, PUT, DELETE и другие. Он позволяет передавать параметры и данные между страницами или функциями, что открывает много возможностей для создания динамического поведения и взаимодействия веб-приложения с пользователем.

Таким образом, роутер PHP является неотъемлемой частью разработки веб-приложений, предоставляющей удобный способ обработки HTTP-запросов и маршрутизации их на соответствующие обработчики. Он позволяет создавать гибкие и масштабируемые приложения, которые легко поддерживать и модифицировать.

Зачем нужен роутер PHP?

Роутер PHP помогает обрабатывать входящие запросы и определять, какую функцию или контроллер должно быть вызвано для обработки каждого конкретного запроса. Он позволяет разработчикам определить логику маршрутизации и правила, основываясь на URL-адресе или других параметрах запроса.

Основная задача роутера PHP — связать запросы URL-адресов с соответствующими контроллерами, которые обрабатывают запрос и генерируют HTML-страницу для ответа. Он позволяет создавать более гибкую и организованную структуру приложения, разделяя его на отдельные модули или действия.

Роутер PHP также может обеспечивать различные функции, такие как контроль доступа к определенным страницам, обработка ошибок и перенаправление на другие страницы или действия. Это позволяет создавать более безопасные и надежные веб-приложения.

Кроме того, использование роутера PHP упрощает поддержку и сопровождение приложения в долгосрочной перспективе. При необходимости изменить логику маршрутизации, достаточно внести изменения только в роутер, без необходимости изменения каждой страницы или контроллера отдельно.

Итак, роутер PHP является неотъемлемой частью разрабатываемых приложений, обеспечивая эффективную маршрутизацию запросов и создавая гибкую структуру приложения. Он упрощает разработку, обеспечивает безопасность и облегчает поддержку приложения.

Как пользоваться роутером PHP?

Для использования роутера PHP вам понадобится:

  1. Подключить файл с определением маршрутов к вашему проекту.
  2. Определить маршруты, указав соответствующие обработчики для каждого из них.
  3. Запустить процесс обработки запроса с помощью роутера.

Вначале вам нужно подключить файл с определением маршрутов к вашему проекту. Этот файл будет содержать код, который определяет все возможные маршруты и соответствующие им обработчики. Вы можете назвать этот файл как угодно, например, routes.php, и подключить его с помощью команды include или require.

Далее вы должны определить маршруты в этом файле. Каждый маршрут состоит из пути (URL) и соответствующего ему обработчика (класса или функции), который будет вызываться при обращении к этому пути. Маршруты могут содержать параметры, которые вы можете использовать внутри обработчика.

Например, чтобы определить маршрут для главной страницы, вы можете использовать следующий код:

$router->addRoute('/', 'HomeController@index');

В этом примере мы указываем, что при обращении к корневому пути будет вызываться метод index класса HomeController.

Когда все маршруты определены, вы можете запустить процесс обработки запроса с помощью роутера. Это можно сделать в начале вашего исполняемого скрипта или в фронт-контроллере приложения. Просто вызовите метод dispatch роутера:

$router->dispatch();

Роутер будет анализировать текущий запрос и выбирать подходящий маршрут для обработки. Затем он вызовет соответствующий обработчик и передаст ему все необходимые параметры, если они были определены.

Использование роутера PHP позволяет упростить организацию маршрутизации в вашем приложении, распределить обработку запросов между различными обработчиками и сделать код более модульным и легким для поддержки.

Преимущества и недостатки

Преимущества Недостатки

1. Простота использования. Роутер PHP предлагает удобный и интуитивно понятный синтаксис для определения и настройки маршрутов веб-приложения. Это позволяет разработчикам быстро создавать и изменять пути обработки запросов.

2. Гибкость и масштабируемость. Роутер PHP обладает возможностью создания сложных иерархических маршрутов, а также поддерживает разделение обработки запросов на отдельные контроллеры и действия. Это позволяет разрабатывать крупные и сложные веб-приложения, которые могут легко масштабироваться.

3. Читаемость кода. Благодаря использованию роутера PHP, структура маршрутов становится более понятной и организованной. Разработчики могут легко найти и изменить необходимые пути, что упрощает поддержку проекта.

1. Дополнительная нагрузка на сервер. При использовании роутера PHP происходит дополнительная обработка запросов, что может привести к небольшому снижению производительности сервера. Однако, это влияние обычно незначительно и не оказывает серьезного влияния на работу веб-приложения.

2. Необходимость дополнительной настройки. Для правильной работы роутера PHP требуется настройка маршрутов и их связывание с соответствующими контроллерами и действиями. Несоблюдение правильной конфигурации может привести к неправильной обработке запросов или возникновению ошибок.

В целом, роутер PHP является мощным и удобным инструментом для управления маршрутизацией веб-приложения. Его использование помогает создавать структурированный код, упрощает разработку и облегчает поддержку проектов.

Latest Stable Version
Total Downloads
Build Status
Coverage Status
License

PhpRouter

PhpRouter is a powerful, lightweight, and very fast HTTP URL router for PHP projects.

Some of the provided features:

  • Route parameters
  • Predefined route parameter patterns
  • Middleware
  • Closure and class controllers/middleware
  • Route groups (by prefix, middleware, and domain)
  • Route naming (and generating route by name)
  • PSR-7 requests and responses
  • Views (simple PHP/HTML views)
  • Multiple (sub)domains (using regex patterns)
  • Custom HTTP methods
  • Integrated with an IoC Container (PhpContainer)
  • Method and constructor auto-injection of Request, Route, Url, etc

The current version requires PHP v7.4 or newer versions including v8.*.

Contents

  • Versions
  • Documentation
    • Installation
    • Configuration
    • Getting Started
    • HTTP Methods
    • Controllers
    • Route Parameters
    • Requests and Responses
    • Views
    • Route Groups
    • Middleware
    • Domains and Subdomains
    • Route Names
    • Current Route
    • Error Handling
  • License

Versions

  • v5.x.x (Current, Supported)
  • v4.x.x
  • v3.x.x
  • v2.x.x
  • v1.x.x

Documentation

Installation

Install Composer and run following command in your project’s root directory:

composer require miladrahimi/phprouter "5.*"

Configuration

First of all,
you need to configure your webserver to handle all the HTTP requests with a single PHP file like the index.php file.
Here you can see sample configurations for NGINX and Apache HTTP Server.

  • NGINX configuration sample:

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
  • Apache .htaccess sample:

    <IfModule mod_rewrite.c>
        <IfModule mod_negotiation.c>
            Options -MultiViews
        </IfModule>
    
        RewriteEngine On
    
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)/$ /$1 [L,R=301]
    
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^ index.php [L]
    </IfModule>
    

Getting Started

It’s so easy to work with PhpRouter! Just take a look at the following example.

  • JSON API Example:

    use MiladRahimi\PhpRouter\Router;
    use Laminas\Diactoros\Response\JsonResponse;
    
    $router = Router::create();
    
    $router->get('/', function () {
        return new JsonResponse(['message' => 'ok']);
    });
    
    $router->dispatch();
  • View Example:

    use MiladRahimi\PhpRouter\Router;
    use MiladRahimi\PhpRouter\View\View
    
    $router = Router::create();
    $router->setupView('/../views');
    
    $router->get('/', function (View $view) {
        return $view->make('profile', ['user' => 'Jack']);
    });
    
    $router->dispatch();

HTTP Methods

The following example illustrates how to declare different routes for different HTTP methods.

use MiladRahimi\PhpRouter\Router;

$router = Router::create();

$router->get('/', function () { /* ... */ });
$router->post('/', function () { /* ... */ });
$router->put('/', function () { /* ... */ });
$router->patch('/', function () { /* ... */ });
$router->delete('/', function () { /* ... */ });

$router->dispatch();

You can use the define() method for other HTTP methods like this example:

use MiladRahimi\PhpRouter\Router;

$router = Router::create();

$router->define('GET', '/', function () { /* ... */ });
$router->define('OPTIONS', '/', function () { /* ... */ });
$router->define('CUSTOM', '/', function () { /* ... */ });

$router->dispatch();

If you don’t care about HTTP verbs, you can use the any() method.

use MiladRahimi\PhpRouter\Router;

$router = Router::create();

$router->any('/', function () {
    return 'This is Home! No matter what the HTTP method is!';
});

$router->dispatch();

Controllers

Closure Controllers

use MiladRahimi\PhpRouter\Router;

$router = Router::create();

$router->get('/', function () {
    return 'This is a closure controller!';
});

$router->dispatch();

Class Method Controllers

use MiladRahimi\PhpRouter\Router;

class UsersController
{
    function index()
    {
        return 'Class: UsersController & Method: index';
    }

    function handle()
    {
        return 'Class UsersController.';
    }
}

$router = Router::create();

// Controller: Class=UsersController Method=index()
$router->get('/method', [UsersController::class, 'index']);

// Controller: Class=UsersController Method=handle()
$router->get('/class', UsersController::class);

$router->dispatch();

Route Parameters

A URL might have one or more variable parts like product IDs on a shopping website.
We call it a route parameter.
You can catch them by controller method arguments like the example below.

use MiladRahimi\PhpRouter\Router;

$router = Router::create();

// Required parameter
$router->get('/post/{id}', function ($id) {
    return "The content of post $id";
});

// Optional parameter
$router->get('/welcome/{name?}', function ($name = null) {
    return 'Welcome ' . ($name ?: 'Dear User');
});

// Optional parameter, Optional / (Slash)!
$router->get('/profile/?{user?}', function ($user = null) {
    return ($user ?: 'Your') . ' profile';
});

// Optional parameter with default value
$router->get('/roles/{role?}', function ($role = 'guest') {
    return "Your role is $role";
});

// Multiple parameters
$router->get('/post/{pid}/comment/{cid}', function ($pid, $cid) {
    return "The comment $cid of the post $pid";
});

$router->dispatch();

Route Parameter Patterns

In default, route parameters can have any value, but you can define regex patterns to limit them.

use MiladRahimi\PhpRouter\Router;

$router = Router::create();

// "id" must be numeric
$router->pattern('id', '[0-9]+');

$router->get('/post/{id}', function (int $id) { /* ... */ });

$router->dispatch();

Requests and Responses

PhpRouter uses laminas-diactoros
(formerly known as zend-diactoros)
package (v2) to provide PSR-7
request and response objects to your controllers and middleware.

Requests

You can catch the request object in your controllers like this example:

use MiladRahimi\PhpRouter\Router;
use Laminas\Diactoros\ServerRequest;
use Laminas\Diactoros\Response\JsonResponse;

$router = Router::create();

$router->get('/', function (ServerRequest $request) {
    $method  = $request->getMethod();
    $uriPath = $request->getUri()->getPath();
    $headers = $request->getHeaders();
    $queryParameters = $request->getQueryParams();
    $bodyContents    = $request->getBody()->getContents();
    // ...
});

$router->dispatch();

Responses

The example below illustrates the built-in responses.

use Laminas\Diactoros\Response\RedirectResponse;
use MiladRahimi\PhpRouter\Router;
use Laminas\Diactoros\Response\EmptyResponse;
use Laminas\Diactoros\Response\HtmlResponse;
use Laminas\Diactoros\Response\JsonResponse;
use Laminas\Diactoros\Response\TextResponse;

$router = Router::create();

$router->get('/html/1', function () {
    return '<html>This is an HTML response</html>';
});
$router->get('/html/2', function () {
    return new HtmlResponse('<html>This is also an HTML response</html>', 200);
});
$router->get('/json', function () {
    return new JsonResponse(['error' => 'Unauthorized!'], 401);
});
$router->get('/text', function () {
    return new TextResponse('This is a plain text...');
});
$router->get('/empty', function () {
    return new EmptyResponse(204);
});
$router->get('/redirect', function () {
    return new RedirectResponse('https://miladrahimi.com');
});

$router->dispatch();

Views

You might need to create a classic-style website that uses views.
PhpRouter has a simple feature for working with PHP/HTML views.
Look at the following example.

use MiladRahimi\PhpRouter\Router;
use MiladRahimi\PhpRouter\View\View

$router = Router::create();

// Setup view feature and set the directory of view files
$router->setupView(__DIR__ . '/../views');

$router->get('/profile', function (View $view) {
    // It looks for a view with path: __DIR__/../views/profile.phtml
    return $view->make('profile', ['user' => 'Jack']);
});

$router->get('/blog/post', function (View $view) {
    // It looks for a view with path: __DIR__/../views/blog/post.phtml
    return $view->make('blog.post', ['post' => $post]);
});

$router->dispatch();

There is also some points:

  • View files must have the «.phtml» extension (e.g. profile.phtml).
  • You can separate directories with . (e.g. blog.post for blog/post.phtml).

View files are pure PHP or mixed with HTML.
You should use PHP language with template style in the view files.
This is a sample view file:

<h1><?php echo $title ?></h1>
<ul>
    <?php foreach ($posts as $post): ?>
        <li><?php echo $post['content'] ?></li>
    <?php endforeach ?>
</ul>

Route Groups

You can categorize routes into groups.
The groups can have common attributes like middleware, domain, or prefix.
The following example shows how to group routes:

use MiladRahimi\PhpRouter\Router;

$router = Router::create();

// A group with uri prefix
$router->group(['prefix' => '/admin'], function (Router $router) {
    // URI: /admin/setting
    $router->get('/setting', function () {
        return 'Setting Panel';
    });
});

// All of group attributes together!
$attributes = [
    'prefix' => '/admin',
    'domain' => 'shop.example.com',
    'middleware' => [AuthMiddleware::class],
];

$router->group($attributes, function (Router $router) {
    // URL: http://shop.example.com/admin/users
    // Domain: shop.example.com
    // Middleware: AuthMiddleware
    $router->get('/users', [UsersController::class, 'index']);
});

$router->dispatch();

The group attributes will be explained later in this documentation.

You can use Attributes enum, as well.

Middleware

PhpRouter supports middleware.
You can use it for different purposes, such as authentication, authorization, throttles, and so forth.
Middleware runs before and after controllers, and it can check and manipulate requests and responses.

Here you can see the request lifecycle considering some middleware:

[Request]  ↦ Router ↦ Middleware 1 ↦ ... ↦ Middleware N ↦ Controller
                                                              ↧
[Response] ↤ Router ↤ Middleware 1 ↤ ... ↤ Middleware N ↤ [Response]

To declare a middleware, you can use closures and classes just like controllers.
To use the middleware, you must group the routes and mention the middleware in the group attributes.
Caution! The middleware attribute in groups takes an array of middleware, not a single one.

use MiladRahimi\PhpRouter\Router;
use Psr\Http\Message\ServerRequestInterface;
use Laminas\Diactoros\Response\JsonResponse;

class AuthMiddleware
{
    public function handle(ServerRequestInterface $request, Closure $next)
    {
        if ($request->getHeader('Authorization')) {            
            // Call the next middleware/controller
            return $next($request);
        }

        return new JsonResponse(['error' => 'Unauthorized!'], 401);
    }
}

$router = Router::create();

// The middleware attribute takes an array of middleware, not a single one!
$router->group(['middleware' => [AuthMiddleware::class]], function(Router $router) {
    $router->get('/admin', function () {
        return 'Admin API';
    });
});

$router->dispatch();

As you can see, the middleware catches the request and the $next closure.
The closure calls the next middleware or the controller if no middleware is left.
The middleware must return a response, as well.
A middleware can break the lifecycle and return a response itself,
or it can call the $next closure to continue the lifecycle.

Domains and Subdomains

Your application may serve different services on different domains or subdomains.
In this case, you can specify the domain or subdomain for your routes.
See this example:

use MiladRahimi\PhpRouter\Router;

$router = Router::create();

// Domain
$router->group(['domain' => 'shop.com'], function(Router $router) {
    $router->get('/', function () {
        return 'This is shop.com';
    });
});

// Subdomain
$router->group(['domain' => 'admin.shop.com'], function(Router $router) {
    $router->get('/', function () {
        return 'This is admin.shop.com';
    });
});

// Subdomain with regex pattern
$router->group(['domain' => '(.*).example.com'], function(Router $router) {
    $router->get('/', function () {
        return 'This is a subdomain';
    });
});

$router->dispatch();

Route Names

You can assign names to your routes and use them in your codes instead of the hard-coded URLs.
See this example:

use MiladRahimi\PhpRouter\Router;
use Laminas\Diactoros\Response\JsonResponse;
use MiladRahimi\PhpRouter\Url;

$router = Router::create();

$router->get('/about', [AboutController::class, 'show'], 'about');
$router->get('/post/{id}', [PostController::class, 'show'], 'post');
$router->get('/links', function (Url $url) {
    return new JsonResponse([
        'about' => $url->make('about'),             /* Result: /about  */
        'post1' => $url->make('post', ['id' => 1]), /* Result: /post/1 */
        'post2' => $url->make('post', ['id' => 2])  /* Result: /post/2 */
    ]);
});

$router->dispatch();

Current Route

You might need to get information about the current route in your controller or middleware.
This example shows how to get this information.

use MiladRahimi\PhpRouter\Router;
use Laminas\Diactoros\Response\JsonResponse;
use MiladRahimi\PhpRouter\Routing\Route;

$router = Router::create();

$router->get('/{id}', function (Route $route) {
    return new JsonResponse([
        'uri'    => $route->getUri(),            /* Result: "/1" */
        'name'   => $route->getName(),           /* Result: "sample" */
        'path'   => $route->getPath(),           /* Result: "/{id}" */
        'method' => $route->getMethod(),         /* Result: "GET" */
        'domain' => $route->getDomain(),         /* Result: null */
        'parameters' => $route->getParameters(), /* Result: {"id": "1"} */
        'middleware' => $route->getMiddleware(), /* Result: []  */
        'controller' => $route->getController(), /* Result: {}  */
    ]);
}, 'sample');

$router->dispatch();

IoC Container

PhpRouter uses PhpContainer to provide an IoC container for the package itself and your application’s dependencies.

How does PhpRouter use the container?

PhpRouter binds route parameters, HTTP Request, Route (Current route), Url (URL generator), Container itself.
The controller method or constructor can resolve these dependencies and catch them.

How can your app use the container?

Just look at the following example.

use MiladRahimi\PhpContainer\Container;
use MiladRahimi\PhpRouter\Router;

$router = Router::create();

$router->getContainer()->singleton(Database::class, MySQL::class);
$router->getContainer()->singleton(Config::class, JsonConfig::class);

// Resolve directly
$router->get('/', function (Database $database, Config $config) {
    // Use MySQL and JsonConfig...
});

// Resolve container
$router->get('/', function (Container $container) {
    $database = $container->get(Database::class);
    $config = $container->get(Config::class);
});

$router->dispatch();

Check PhpContainer for more information about this powerful IoC container.

Error Handling

Your application runs through the Router::dispatch() method.
You should put it in a try block and catch exceptions.
It throws your application and PhpRouter exceptions.

use MiladRahimi\PhpRouter\Router;
use MiladRahimi\PhpRouter\Exceptions\RouteNotFoundException;
use Laminas\Diactoros\Response\HtmlResponse;

$router = Router::create();

$router->get('/', function () {
    return 'Home.';
});

try {
    $router->dispatch();
} catch (RouteNotFoundException $e) {
    // It's 404!
    $router->getPublisher()->publish(new HtmlResponse('Not found.', 404));
} catch (Throwable $e) {
    // Log and report...
    $router->getPublisher()->publish(new HtmlResponse('Internal error.', 500));
}

PhpRouter throws the following exceptions:

  • RouteNotFoundException if PhpRouter cannot find any route that matches the user request.
  • InvalidCallableException if PhpRouter cannot invoke the controller or middleware.

The RouteNotFoundException should be considered 404 Not found error.

License

PhpRouter is initially created by Milad Rahimi and released under the MIT License.

  • Что такое роутер в информатике определение кратко
  • Что такое роутер для интернета и как к нему подключить ноутбук
  • Что такое роутер билайн smart box
  • Что такое роутер для интернета и для чего он нужен
  • Что такое роутер бит с