agashe/sigmaphp-router

PHP 路由器

0.1.1 2024-09-12 06:47 UTC

This package is auto-updated.

Last update: 2024-09-12 06:49:27 UTC


README

SigmaPHP-Router 是一个快速简单的 PHP 路由器,您可以用它为您的项目提供用户友好的 URL,您可以在简单功能风格中构建您的应用程序,编写 RESTful API 服务或构建一个完全功能性的 MVC。

特性

  • 支持占位符参数,例如 {name}
  • 可以在路由中使用可选参数
  • 支持所有 HTTP 方法 GET、POST、PUT 等
  • 路由可以接受多种 HTTP 方法
  • 支持 any 方法,因此路由可以接受所有 HTTP 方法
  • 使用正则表达式进行路由验证
  • 操作可以实现为常规函数或控制器的方法
  • 支持单一操作控制器
  • 中间件,可以在您的路由之前运行
  • 支持中间件和前缀的路由分组
  • 使用路由名称生成 URL
  • 默认页面未找到(404)处理程序,您可以使用自己的处理程序

安装

composer require agashe/sigmaphp-router

配置

根据您的服务器,您可能需要使用提供的其中一个服务器配置,包括用于 Apache、Nginx、Lighttpd 和 IIS 的路由器配置文件。

要使用任何这些服务器中的路由器,只需将 configs 文件夹中的相应配置文件复制到您项目的根文件夹。

例如,如果您正在使用 Apache 服务器,则复制 apache_htaccess 文件,并将其重命名为正确的名称 .htaccess

请注意:所有提供的配置文件都假设您应用程序的主入口点是位于项目目录根路径的 index.php。如果您对项目有不同的设置,请检查配置并确保它指向正确的路径。

因此,如果 index.php 位于 public 文件夹下,则在 .htaccess 文件中将 index.php 更改为 public/index.php,对于其他服务器也是如此。

文档

基本设置

为了开始在您的应用程序中使用 SigmaPHP-Router,在应用程序的主入口点(例如 index.php),您首先需要定义路由数组,然后将该数组传递给构造函数,最后调用 run() 方法。

<?php

require 'vendor/autoload.php';

use SigmaPHP\Router\Router;

$routes = [
    [
        'name' => 'users.profile',
        'path' => '/users/profile',
        'method' => 'get',
        'controller' => UserController::class,
        'action' => 'profile',
    ],
];

// initialize the router
$router = new Router($routes);

// fire the router
$router->run();

或者您可以将路由保存在单独的文件中,并在您的应用程序中加载该文件。更好的是,您可以拥有多个路由文件,每个文件服务于不同的目的。

web.php

<?php

return [
    [
        'name' => 'users.profile',
        'path' => '/users/profile',
        'method' => 'get',
        'controller' => UserController::class,
        'action' => 'profile',
    ],
];

api.php

<?php

return [
    [
        'name' => 'api.users.profile',
        'path' => '/api/v1/users/profile',
        'method' => 'get',
        'controller' => UserApiController::class,
        'action' => 'profileJson',
    ],
];

最后在 index.php

<?php

require 'vendor/autoload.php';

use SigmaPHP\Router\Router;

$webRoutes = require('web.php');
$apiRoutes = require('api.php');

// initialize the router
$router = new Router(array_merge($webRoutes, $apiRoutes));

// fire the router
$router->run();

要定义新路由,只需将路由数组附加到路由数组中,有效的路由至少应该包含一个路径和一个操作

$routes = [
    [
        'path' => '/users/profile',
        'action' => 'get_user_profile',
    ],
];

路由的名称是可选的,尽管如此,建议为您的路由命名,这样它们就更容易处理,例如使用路由的名称生成 URL。

基础路径

如果您的应用程序位于域名子文件夹中,例如 http://localhost/my-app,则您可以在路由构造函数中使用第二个参数设置根路径。

<?php

require 'vendor/autoload.php';

use SigmaPHP\Router\Router;

$routes = [
    [
        'name' => 'users.profile',
        'path' => '/users/profile',
        'method' => 'get',
        'controller' => UserController::class,
        'action' => 'profile',
    ],
];

// define app base path
const BASE_PATH = '/my-app';

// initialize the router
$router = new Router($routes, BASE_PATH);

// fire the router
$router->run();

HTTP 方法

SigmaPHP-Router 支持所有 HTTP 方法 GET、POST、PUT、DELETE 等,单个路由可以支持一个或多个 HTTP 方法

$routes = [
    [
        'name' => 'users.profile',
        'path' => '/users/profile',
        'method' => 'get,post',
        'controller' => UserController::class,
        'action' => 'profile',
    ],
];

此外,SigmaPHP-Router还提供了一个特殊的请求方法类型any,允许路由接受所有HTTP方法。

$routes = [
    [
        'name' => 'users.profile',
        'path' => '/users/profile',
        'method' => 'any',
        'controller' => UserController::class,
        'action' => 'profile',
    ],
];

如果没有提供HTTP方法,则路由的HTTP方法将自动设置为GET。

参数

路由参数遵循占位符风格(类似于Laravel)。

$routes = [
    [
        'name' => 'admin.users.address',
        'path' => '/admin/users/{user_id}/addresses/{address_id}',
        'method' => 'get',
        'controller' => AdminPanelUserController::class,
        'action' => 'getUserAddressDetails',
    ],
];

..... In AdminPanelUserController.php

public function getUserAddressDetails($userId, $addressId) {
    ...
}

此外,可以通过在参数后添加?来使用可选参数,但此选项只能用于路由的最后一个参数。

$routes = [
    [
        'name' => 'products.list',
        'path' => '/products/{id?}',
        'method' => 'get',
        'controller' => ProductController::class,
        'action' => 'list',
    ],
];

因此,此路由中的id可以省略,调用/products/products/15都是可以的。

最后,别忘了在您的操作中处理可选参数,为操作添加一个默认值。

..... In ProductController.php

public function list($id = null) {
    ...
}

验证

可以向路由中添加验证规则,以正则表达式的形式。

$routes = [
    [
        'name' => 'orders.show',
        'path' => '/orders/details/{order_id}',
        'method' => 'get',
        'controller' => OrderController::class,
        'action' => 'show',
        'validation' => [
            'order_id' => '[0-9]+'
        ]
    ],
];

在上面的例子中,路由将仅匹配仅包含数字的order_id,所以类似/orders/details/abcd的URL将不会匹配,路由将返回404 - 页面未找到。

操作

在SigmaPHP-Router中,操作是执行路由功能的处理器。

操作分为两类,第一类是基于控制器的,它们仅仅是包含多个方法的类,通常负责处理同一模型或功能组内的任务,例如PostControllerUserLoginController

正如我们之前看到的例子,我们需要传递控制器名称和方法名称。

$routes = [
    [
        'name' => 'orders.show',
        'path' => '/orders/details/{order_id}',
        'method' => 'get',
        'controller' => OrderController::class,
        'action' => 'show',
    ],
];

我们使用特殊的常量::class来获取包括命名空间在内的完整名称。如果您愿意,也可以写出完整的路径,例如。

$routes = [
    [
        'name' => 'orders.show',
        'path' => '/orders/details/{order_id}',
        'method' => 'get',
        'controller' => App\Web\Controllers\OrderController,
        'action' => 'show',
    ],
];

第二种类型的操作是基于函数的,在这种情况下,您只需添加函数名称而不需要控制器,路由将直接调用该函数,例如。

$routes = [
    [
        'name' => 'about_page',
        'path' => '/about',
        'method' => 'get',
        'action' => 'create_about_page',
    ],
];

.... somewhere in your application define the function and call it either in the same index.php or another file

// pages.php
<?php

function create_about_page() {
    print "About Us";
}

最后,SigmaPHP-Router还支持单操作控制器,因此不需要传递操作名称,路由将自动搜索PHP魔术方法__invoke()来运行。

$routes = [
    [
        'name' => 'notification.send_email',
        'path' => '/notification/send-email',
        'method' => 'post',
        'controller' => SendEmailController::class,
    ],
];

在SendEmailController中

// SendEmailController.php
<?php

class SendEmailController
{
   public function __invoke()
   {
        // .... some code to send email
   } 
}

中间件

通常在任何应用程序中,您都需要在允许用户执行操作之前运行一些检查,例如检查用户是否登录,是否有适当的权限等。

因此,SigmaPHP-Router提供在执行路由操作之前调用中间件的能力。

$routes = [
    [
        'name' => 'orders.create',
        'path' => '/orders',
        'method' => 'post',
        'middlewares' => [
            [AuthMiddleware::class, 'handler'],
            [UserCanCreateOrderMiddleware::class, 'check'],
        ],
        'controller' => OrderController::class,
        'action' => 'create'
    ],
];

对于基于类的中间件,路由将需要中间件类名称和将被执行的方法名称。

此外,中间件也可以编写为常规函数,在这种情况下,我们传递一个函数名称数组。

$routes = [
    [
        'name' => 'orders.create',
        'path' => '/orders',
        'method' => 'post',
        'middlewares' => ['is_user_auth', 'check_user_permissions'],
        'controller' => OrderController::class,
        'action' => 'create'
    ],
];

创建中间件类/函数完全取决于您的应用程序,所以您的中间件可能包含类似的内容。

<?php

class AuthMiddleware
{
    public function handler()
    {
        session_start();

        if (empty($_SESSION['user])) {
            header('Location: http://example.com');
            exit();
        }
    }
}

路由分组

分组路由是任何路由器的必备功能,因此您可以将某些前缀或中间件应用于一组路由。

要创建新的路由分组,使用以下架构

$routes = [
    [
        'group' => 'api',
        'prefix' => '/api/v1/',
        'middlewares' => [
            [AuthMiddleware::class, 'handler'],
            [UserAccountIsActiveMiddleware::class, 'handler'],
        ],
        'routes' => [
            [
                'name' => 'users.profile',
                'path' => '/users/profile',
                'method' => 'get',
                'middlewares' => [
                    [CheckIfUserCanEditProfileMiddleware::class, 'handler'],
                ],
                'controller' => UserApiController::class,
                'action' => 'profile'
            ],
        ]
    ],
];

分组所需的项目只有一个,即分组名称和路由数组。名称将添加到其所有路由中,因此在上面的例子中,最终的路由名称将是:api.users.profile,路由路径:/api/v1/users/profile

prefixmiddlewares都是可选的,路由分组可以具有前缀、中间件、两者都有或都没有。

对于路由定义,没有变化,所有功能都按常规路由实现。

请注意:SigmaPHP-Router不支持子分组,因此您不能在另一个路由组内部定义路由组!

页面未找到处理

默认情况下,如果请求的URI不匹配,路由器将返回404 HTTP状态码,并显示简单的消息 404,请求的URL未找到

您可以通过将自定义处理程序名称作为参数传递给 setPageNotFoundHandler 方法来更改此默认行为。

<?php

require 'vendor/autoload.php';

use SigmaPHP\Router\Router;

$routes = [
    [
        'name' => 'users.profile',
        'path' => '/users/profile',
        'method' => 'get',
        'controller' => UserController::class,
        'action' => 'profile',
    ],
];

// initialize the router
$router = new Router($routes);

// set custom 404 (Page Not Found) handler
$router->setPageNotFoundHandler('my_custom_404_handler');

// fire the router
$router->run();

.... and somewhere in your code , you define that function :

function my_custom_404_handler() {
    http_response_code(404);
    echo "<h1>My custom message</h1>";
    exit();
}

因此,现在您可以添加自定义的404消息、页面设计或重定向用户到另一个路由。

通常,您可以使用类代替函数处理程序,因此您需要传递类名和方法名。

// set custom 404 (Page Not Found) handler
$router->setPageNotFoundHandler([
    MyCustomPageNotFoundHandler::class, 'handle'
]);

URL生成

在许多情况下,您需要一种创建模型URL的方法,例如显示订单详情的链接。SigmaPHP-Router提供了一个名为 url 的方法,它接受路由名称和参数数组,并生成URL。让我们看看一个例子。

$routes = [
    [
        'name' => 'order.items.details',
        'path' => '/order/{order_id}/items/{item_id?}',
        'method' => 'get',
        'controller' => OrderController::class,
        'action' => 'getOrderItems',
    ],
];

要为上述路由生成URL

$orderId = 5;
$itemId = 10;

$itemsURL = $router->url('order.items.details', [
    'order_id' => $orderId,
    'item_id' => $itemId,
]);

..... if we print $itemURL :
http://localhost/order/5/items/10

路由器将自动添加主机并检查是否启用了https。

如果您的路由不需要参数或接受可选参数,您可以省略第二个参数。

$routes = [
    [
        'name' => 'print_terms_of_usage',
        'path' => '/terms-of-usage',
        'method' => 'get',
        'action' => 'print_terms_of_usage',
    ],
];

$pageURL = $router->url('print_terms_of_usage');

..... if we print $pageURL :
http://localhost/terms-of-usage

示例

$routes = [
    [
        'name' => 'home',
        'path' => '/',
        'method' => 'get',
        'action' => 'home_page',
    ],
    [
        'name' => 'contact_us.show',
        'path' => '/contact-us',
        'method' => 'get',
        'controller' => ContactUsController::class,
        'action' => 'showContactUsForm'
    ],
    [
        'name' => 'contact_us.submit',
        'path' => '/contact-us',
        'method' => 'post',
        'controller' => ContactUsController::class,
        'action' => 'submitContactUsForm'
    ],
    [
        'group' => 'posts',
        'prefix' => 'posts/',
        'middlewares' => [
            [AuthMiddleware::class, 'handler'],
            [UserIsActiveMiddleware::class, 'handler'],
            [UserCanControlPostsMiddleware::class, 'handler'],
        ],
        'routes' => [
            [
                'name' => 'list',
                'path' => '/{id?}',
                'method' => 'get',
                'controller' => PostController::class,
                'action' => 'index',
                'validation' => [
                    'id' => '[0-9]+'
                ]
            ],
            [
                'name' => 'create',
                'path' => '/create',
                'method' => 'get,post',
                'controller' => PostController::class,
                'action' => 'create'
            ],
            [
                'name' => 'update',
                'path' => '/update/{id}',
                'method' => 'get,patch',
                'controller' => PostController::class,
                'action' => 'update',
                'validation' => [
                    'id' => '[0-9]+'
                ]
            ],
            [
                'name' => 'delete',
                'path' => '/{id}',
                'method' => 'delete',
                'controller' => PostController::class,
                'action' => 'delete',
                'validation' => [
                    'id' => '[0-9]+'
                ]
                'middlewares' => [
                    [CheckPostIsNotPublishedMiddleware::class, 'handler'],
                ],
            ],
        ]
    ]
];

许可

(SigmaPHP-Router) 在MIT许可条款下发布。