跳转到内容

路由组件


概览

The Phalcon\Mvc\Router组件允许你定义映射到接收并处理请求的控制器或处理器的路由。路由器有两种模式:MVC 模式和仅匹配模式。第一个模式适合与 MVC 应用一起使用。

<?php

use Phalcon\Mvc\Router;

$router = new Router();

$router->add(
    '/admin/invoices/list',
    [
        'controller' => 'invoices',
        'action'     => 'list',
    ]
);

$router->handle(
    $_SERVER["REQUEST_URI"]
);

常量

有两个常量可用于Phalcon\Mvc\Router组件,用于定义路由在处理堆栈中的位置。

  • POSITION_FIRST
  • POSITION_LAST

方法

public function __construct(
    bool $defaultRoutes = true
)

Phalcon\Mvc\Router 构造函数

public function add(
    string $pattern, 
    mixed $paths = null, 
    mixed $httpMethods = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个没有 HTTP 限制的路由到路由器

use Phalcon\Mvc\Router;

$router->add("/about", "About::index");

$router->add(
    "/about",
    "About::index",
    ["GET", "POST"]
);

$router->add(
    "/about",
    "About::index",
    ["GET", "POST"],
    Router::POSITION_FIRST
);

public function addConnect(
    string $pattern, 
    mixed $paths = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个只有当 HTTP 方法是时才匹配的路由到路由器CONNECT

public function addDelete(
    string $pattern, 
    mixed $paths = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个只有当 HTTP 方法是时才匹配的路由到路由器DELETE

public function addGet(
    string $pattern, 
    mixed $paths = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个只有当 HTTP 方法是时才匹配的路由到路由器GET

public function addHead(
    string $pattern, 
    mixed $paths = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个只有当 HTTP 方法是时才匹配的路由到路由器HEAD

public function addOptions(
    string $pattern, 
    mixed $paths = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个只有当 HTTP 方法是时才匹配的路由到路由器OPTIONS

public function addPatch(
    string $pattern, 
    mixed $paths = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个只有当 HTTP 方法是时才匹配的路由到路由器PATCH

public function addPost(
    string $pattern, 
    mixed $paths = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个只有当 HTTP 方法是时才匹配的路由到路由器POST

public function addPurge(
    string $pattern, 
    mixed $paths = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个只有当 HTTP 方法是时才匹配的路由到路由器PURGE(Squid 和 Varnish 支持)

public function addPut(
    string $pattern, 
    mixed $paths = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个只有当 HTTP 方法是时才匹配的路由到路由器PUT

public function addTrace(
    string $pattern, 
    mixed $paths = null, 
    int $position = Router::POSITION_LAST
): RouteInterface
添加一个只有当 HTTP 方法是时才匹配的路由到路由器TRACE

public function attach(
    RouteInterface $route, 
    int $position = Router::POSITION_LAST
): RouterInterface
将 Route 对象附加到路由堆栈中。

use Phalcon\Mvc\Router;
use Phalcon\Mvc\Router\Route;

class CustomRoute extends Route {
     // ...
}

$router = new Router();

$router->attach(
    new CustomRoute(
        "/about", 
        "About::index", 
        ["GET", "HEAD"]
    ),
    Router::POSITION_FIRST
);

public function clear(): void
移除所有预定义的路由

public function getActionName(): string
返回已处理的动作名称

public function getControllerName(): string
返回已处理的控制器名称

public function getMatchedRoute(): RouteInterface
返回匹配处理URI的路由

public function getMatches(): array
返回正则表达式中匹配的子表达式

public function getModuleName(): string
返回已处理的模块名称

public function getNamespaceName(): string
返回已处理的命名空间名称

public function getParams(): array
返回已处理的参数

public function getRouteById(
    mixed $id
): RouteInterface | bool
根据ID返回路由对象

public function getRouteByName(
    string $name
): RouteInterface | bool
根据名称返回路由对象

public function getRoutes(): RouteInterface[]
返回在路由器中定义的所有路由

public function handle(string $uri): void
处理从重写引擎接收到的路由信息

$router->handle("/posts/edit/1");

public function isExactControllerName(): bool
返回是否不应修改控制器名称

public function mount(
    GroupInterface $group
): RouterInterface
在路由器中挂载一组路由

public function notFound(
    mixed $paths
): RouterInterface
设置当未匹配到任何定义的路由时返回的一组路径

public function removeExtraSlashes(
    bool $remove
): RouterInterface
设置路由器是否必须移除已处理路由中的额外斜杠

public function setDefaultAction(
    string $actionName
): RouterInterface
设置默认的动作名称

public function setDefaultController(
    string $controllerName
): RouterInterface
设置默认控制器名

public function setDefaultModule(
    string $moduleName
): RouterInterface
设置默认模块名

public function setDefaultNamespace(
    string $namespaceName
): RouterInterface
设置默认命名空间的名称

public function setDefaults(
    array $defaults
): RouterInterface
设置默认路径数组。如果路由缺少路径,路由器将使用此处定义的路径。此方法不应用于设置404路由

$router->setDefaults(
    [
        "module" => "common",
        "action" => "index",
    ]
);

public function getDefaults(): array
返回默认参数数组

public function wasMatched(): bool
检查路由器是否匹配任何已定义的路由

定义路由

Phalcon\Mvc\Router提供了高级路由功能。在 MVC 模式下,你可以定义路由并将它们映射到所需的控制器/动作。一个路由定义如下所示:

<?php

use Phalcon\Mvc\Router;

$router = new Router();

$router->add(
    '/admin/invoices/list',
    [
        'controller' => 'invoices',
        'action'     => 'list',
    ]
);

$router->add(
    '/admin/customers/list',
    [
        'controller' => 'customers',
        'action'     => 'list',
    ]
);

$router->handle(
    $_SERVER["REQUEST_URI"]
);

第一个参数是add()方法是你想要匹配的模式,并且可选地,第二个参数是一组路径。在上面的例子中,对于 URI/admin/invoices/listInvoicesController将被加载,并且listAction将会被调用。需要记住的是,路由器不会执行控制器和动作,它只收集这些信息,然后将其转发给Phalcon\Mvc\Dispatcher并由其来执行。

一个应用可以有多个路径,逐个定义路由可能是一项繁琐的任务。Phalcon\Mvc\Router提供了一种更简单的方式来注册路由。

<?php

use Phalcon\Mvc\Router;

$router = new Router();

$router->add(
    '/admin/:controller/:action/:params',
    [
        'controller' => 1,
        'action'     => 2,
        'params'     => 3,
    ]
);

在上面的例子中,我们使用通配符使一个路由适用于多个 URI。例如,访问以下 URL (/admin/customers/view/12345/1) 将产生:

控制器 动作 参数 参数
customers view 12345 1

The add()方法接收一个模式,该模式可以选择性地包含预定义的占位符和正则表达式修饰符。所有的路由模式必须以正斜杠字符开头 (/)。所使用的正则表达式语法与PCRE 正则表达式.

注意

不需要添加正则表达式的定界符。所有路由模式都是不区分大小写的。

第二个参数定义如何将匹配的部分绑定到控制器/动作/参数。匹配的部分是由括号(圆括号)分隔的占位符或子模式。在上面给出的例子中,第一个匹配的子模式 (:controller) 是路由的控制器部分,第二个是动作 (:action), 然后是传递的任何参数 (:params)。

这些占位符使路由表达式更具可读性和更容易理解。支持以下占位符:

占位符 正则表达式 匹配内容
/:module /([a-zA-Z0-9\_\-]+) 仅包含字母数字字符的有效模块名
/:controller /([a-zA-Z0-9\_\-]+) 仅包含字母数字字符的有效控制器名
/:action /([a-zA-Z0-9_-]+) 仅包含字母数字字符的有效动作名
/:params (/.*)* 由斜杠分隔的可选词列表。只能在路由末尾使用此占位符
/:namespace /([a-zA-Z0-9\_\-]+) 单层命名空间名
/:int /([0-9]+) 整数参数

控制器名称会进行驼峰化处理,这意味着字符 (-) 和 (_) 会被移除,并且下一个字符会被转为大写。例如,some_controller被转换为SomeController.

由于你可以使用add()方法添加任意数量的路由,因此添加路由的顺序表示它们的相关性。后添加的路由比之前添加的路由具有更高相关性。在内部,所有定义的路由将以相反的顺序遍历,直到Phalcon\Mvc\Router找到与给定 URI 匹配的那条并进行处理,忽略其余路由。

命名参数

下面的示例演示了如何为路由参数定义名称:

<?php

$router->add(
    //         1     /     2    /    3     /   4
    '/admin/([0-9]{4})/([0-9]{2})/([0-9]{2})/:params',
    [
        'controller' => 'invoices',
        'action'     => 'view',
        'year'       => 1, // ([0-9]{4})
        'month'      => 2, // ([0-9]{2})
        'day'        => 3, // ([0-9]{2})
        'params'     => 4, // :params
    ]
);

在上述示例中,路由没有定义controlleraction。这些将被替换为固定值 (invoicesview)。用户永远不会知道请求所派发到的底层控制器。在控制器中,这些命名参数可以通过以下方式访问:

<?php

use Phalcon\Mvc\Controller;
use Phalcon\Mvc\Dispatcher;

/**
 * @property Dispatcher $dispatcher
 */
class InvoicesController extends Controller
{
    public function viewAction()
    {
        // year
        $year = $this->dispatcher->getParam('year');

        // month
        $month = $this->dispatcher->getParam('month');

        // day
        $day = $this->dispatcher->getParam('day');

        // ...
    }
}

请注意,参数的值是从调度器中获取的。还有另一种方法可以在模式内部创建命名参数:

<?php

$router->add(
    '/admin/{year}/{month}/{day}/{invoiceNo:[0-9]+}',
    [
        'controller' => 'invoices',
        'action'     => 'view',
    ]
);

您可以像之前一样访问它们的值:

<?php

use Phalcon\Mvc\Controller;
use Phalcon\Mvc\Dispatcher;

/**
 * @property Dispatcher $dispatcher
 */
class InvoicesController extends Controller
{
    public function viewAction()
    {
        // year
        $year = $this->dispatcher->getParam('year');

        // month
        $month = $this->dispatcher->getParam('month');

        // day 
        $day = $this->dispatcher->getParam('day');

        // invoiceNo
        $invoiceNo = $this->dispatcher->getParam('invoiceNo');

        // ...
    }
}

简洁语法

Phalcon\Mvc\Router还提供了一种替代性的更简洁的语法。以下示例产生相同的结果:

<?php

$router->add(
    '/admin/{year:[0-9]{4}}/{month:[0-9]{2}}/{day:[0-9]{2}}/:params',
    'Invoices::view'
);

$router->add(
    '/admin/([0-9]{4})/([0-9]{2})/([0-9]{2})/:params',
    [
        'controller' => 'invoices',
        'action'     => 'view',
        'year'       => 1, // ([0-9]{4})
        'month'      => 2, // ([0-9]{2})
        'day'        => 3, // ([0-9]{2})
        'params'     => 4, // :params
    ]
);

数组与简洁语法

可以混合使用数组和简洁语法来定义路由,在这种情况下,请注意命名参数会根据其在路径中的定义位置自动添加到路由路径中:

<?php

$router->add(
    '/admin/{year:[0-9]{4}}/([0-9]{2})/([0-9]{2})/:params',
    [
        'controller' => 'invoices',
        'action'     => 'view',
        'month'      => 2, // ([0-9]{2}) // 2
        'day'        => 3, // ([0-9]{2}) // 3
        'params'     => 4, // :params    // 4
    ]
);
第一个位置必须被跳过,因为它用于命名参数year.

模块

您可以在路径中定义包含模块的路由。这尤其适用于多模块应用程序。您可以定义一个包括模块通配符的默认路由。

<?php

use Phalcon\Mvc\Router;

$router = new Router(false);

$router->add(
    '/:module/:controller/:action/:params',
    [
        'module'     => 1,
        'controller' => 2,
        'action'     => 3,
        'params'     => 4,
    ]
);

使用上述路由时,您需要始终将模块名称作为URL的一部分。例如,对于以下URL:/admin/invoices/view/12345,将会被处理为:

模块 控制器 动作 参数
admin invoices view 12345

或者您可以将特定路由绑定到特定模块:

<?php

$router->add(
    '/login',
    [
        'module'     => 'session',
        'controller' => 'login',
        'action'     => 'index',
    ]
);

$router->add(
    '/invoices/:action',
    [
        'module'     => 'admin',
        'controller' => 'invoices',
        'action'     => 1,
    ]
);

或者将其绑定到特定命名空间:

<?php

$router->add(
    '/:namespace/login',
    [
        'namespace'  => 1,
        'controller' => 'login',
        'action'     => 'index',
    ]
);

需要单独传递完整的命名空间:

<?php

$router->add(
    '/login',
    [
        'namespace'  => 'Admin\Controllers',
        'controller' => 'login',
        'action'     => 'index',
    ]
);

HTTP 方法

当您仅使用add()添加路由时,该路由将对任何HTTP方法启用。有时我们可以限制路由到特定方法。这在创建RESTful应用程序时特别有用。

<?php

// GET
$router->addGet(
    '/invoices/edit/{id}',
    'Invoices::edit'
);

// POST
$router->addPost(
    '/invoices/save',
    'Invoices::save'
);

// POST/PUT
$router->add(
    '/invoices/update',
    'Invoices::update'
)->via(
    [
        'POST',
        'PUT',
    ]
);

转换器

转换器是一段代码,允许您在参数发送给分发器

<?php

$route = $router->add(
    '/products/{slug:[a-z\-]+}',
    [
        'controller' => 'products',
        'action'     => 'show',
    ]
);

$route->convert(
    'slug',
    function ($slug) {
        return str_replace('-', '', $slug);
    }
);
在上面的示例中,参数名称允许带连字符,因此URL可以是/products/new-ipod-nano-generation。该convert方法将把参数转换为newipodnanogeneration.

转换器的另一个用例是当将模型绑定到路由时。这允许直接将模型传递到定义的动作中。

<?php

$route = $router->add(
    '/products/{id}',
    [
        'controller' => 'products',
        'action'     => 'show',
    ]
);

$route->convert(
    'id',
    function ($id) {
        return Product::findFirstById($id);
    }
);
在上面的示例中,ID通过URL传递,并且我们的转换器从数据库中获取记录并返回它。

如果一组路由有共同的路径,为了便于维护,可以将它们分组。为此,我们使用Phalcon\Mvc\Router\Group组件

<?php

use Phalcon\Mvc\Router;
use Phalcon\Mvc\Router\Group;

$router   = new Router();
$invoices = new RouterGroup(
    [
        'module'     => 'admin',
        'controller' => 'invoices',
    ]
);

$invoices->setPrefix('/invoices');

$invoices->add(
    '/list',
    [
        'action' => 'list',
    ]
);

$invoices->add(
    '/edit/{id}',
    [
        'action' => 'edit',
    ]
);

$invoices->add(
    '/view',
    [
        'controller' => 'common',
        'action'     => 'index',
    ]
);

$router->mount($invoices);
在上面的示例中,我们首先创建一个具有通用模块和控制器的组。然后我们为该组添加前缀为/invoices。然后我们向该组添加更多路由,其中一些不带参数,一些带参数。最后一条路由允许我们使用不同于默认控制器的控制器(common)。最后,我们将该组添加到路由器。

我们可以扩展Phalcon\Mvc\Router\Group组件,并在每个组中注册我们的路由。这使我们能够更好地组织应用程序的路由。

<?php

use Phalcon\Mvc\Router\Group;

class InvoicesRoutes extends Group
{
    public function initialize()
    {
        $this->setPaths(
            [
                'module'    => 'invoices',
                'namespace' => 'Invoices\Controllers',
            ]
        );

        $this->setPrefix('/invoices');

        $this->add(
            '/list',
            [
                'action' => 'list',
            ]
        );

        $this->add(
            '/edit/{id}',
            [
                'action' => 'edit',
            ]
        );

        $this->add(
            '/view',
            [
                'controller' => 'common',
                'action'     => 'index',
            ]
        );
    }
}

现在我们可以在路由器中挂载自定义组类:

<?php

$router->mount(
    new InvoicesRoutes()
);

匹配路由

必须传入有效的URI给路由器,以便它可以处理并找到匹配的路由。默认情况下,路由URI来自重写引擎模块创建的$_GET['_url']变量。几个与Phalcon配合非常出色的重写规则如下:

RewriteEngine On
RewriteCond   %{REQUEST_FILENAME} !-d
RewriteCond   %{REQUEST_FILENAME} !-f
RewriteRule   ^((?s).*)$ index.php?_url=/$1 [QSA,L]

在此配置中,任何对不存在文件或文件夹的请求都将发送到index.php。以下示例展示了如何作为独立组件使用它:

<?php

use Phalcon\Mvc\Router;

$router = new Router();

// ...

$router->handle(
    $_GET["_url"]
);

echo $router->getControllerName();
echo $router->getActionName();

$route = $router->getMatchedRoute();
在上面的示例中,我们首先创建了一个路由器对象。我们可以在之后编写一些代码,比如定义服务、路由等。然后我们从_url全局超变量中获取$_GET元素,之后,我们可以获取控制器名称或者动作名称,甚至获取匹配的路由。

命名路由

添加到路由器的每条路由都会作为Phalcon\Mvc\Router\Route对象存储在内部。该类封装了每条路由的所有细节。例如,我们可以为路径赋予一个名称以在我们的应用中唯一标识它。如果您想从此生成URL的话,这将很有用。

<?php

$route = $router->add(
    '/admin/{year:[0-9]{4}}/{month:[0-9]{2}}/{day:[0-9]{2}}/{id:[0-9]{4}',
    'Invoices::view'
);

$route->setName('invoices-view');

然后,例如使用组件Phalcon\Url我们可以根据定义的名称构建路由:

<?php

// /admin/2019/12/25/1234
echo $url->get(
    [
        'for'   => 'invoices-view',
        'year'  => '2019',
        'month' => '12',
        'day'   => '25',
        'id'    => '1234',
    ]
);

默认行为

Phalcon\Mvc\Router提供了默认的行为,提供了简单的路由功能,总是期望一个URI并匹配以下模式:

/:controller/:action/:params

例如,对于如下的URLhttps://dev.phalcon.od/download/linux/ubuntu.html,此路由器将解释为:

控制器 动作 参数
DownloadController linuxAction ubuntu.html

如果您不希望路由器遵循此行为,则必须通过构造函数传入false来创建路由器。

<?php

use Phalcon\Mvc\Router;

$router = new Router(false);

默认路由

当您的应用程序在没有指定任何路由的情况下被访问时,/路由用来确定必须使用哪些路径来显示应用程序的初始页面

<?php

$router->add(
    '/',
    [
        'controller' => 'index',
        'action'     => 'index',
    ]
);

未找到(404)

如果在路由器中指定的路由没有一个匹配,您可以通过使用notFound方法设置容器。

<?php

$router->notFound(
    [
        'controller' => 'index',
        'action'     => 'fourOhFour',
    ]
);

注意

定义一个404控制器/动作。$router = Phalcon\Mvc\Router(false);

默认值

您可以为module, controller和`action`定义默认值。当路由路径缺少这些元素之一时,路由器将自动使用设置的默认值。

<?php

$router->setDefaultModule('admin');
$router->setDefaultNamespace('Admin\Controllers');
$router->setDefaultController('index');
$router->setDefaultAction('index');

$router->setDefaults(
    [
        'controller' => 'index',
        'action'     => 'index',
    ]
);

结尾斜杠

有时,可能通过额外的/结尾斜杠访问路由。附加的斜杠将在调度器中产生“找不到”的状态,这不是我们想要的。您可以将路由器设置为自动删除处理路由末尾的斜杠。

<?php

use Phalcon\Mvc\Router;

$router = new Router();

$router->removeExtraSlashes(true);

或者,您可以修改特定路由以选择性地接受结尾斜杠:

<?php

$route = $router->add(
    '/admin/:controller/status[/]{0,1}',
    [
        'controller' => 2,
        'action'     => 'status',
    ]
);
在上面的例子中,[/]{0,1}允许可选的结尾斜杠

回调

有时,只有满足特定条件时才应匹配路由。您可以使用beforeMatch回调向路由添加任意条件。如果此函数返回false,该路由将被视为未匹配:

<?php

$route = $router->add(
    '/login',
    [
        'module'     => 'admin',
        'controller' => 'session',
    ]
);

$route->beforeMatch(
    function ($uri, $route) {
        if (true === isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 
            $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'
        ) {
            return false;
        }

        return true;
    }
);
上述代码将检查请求是否通过 AJAX 发起,并返回false如果不是的话

您可以创建一个过滤器类,以便将相同的功能注入到不同的路由中。

<?php

class AjaxFilter
{
    public function check()
    {
        return $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
    }
}

要进行此设置,我们只需将类添加到beforeMatch调用中。

<?php

$route = $router->add(
    '/login',
    [
        'module'     => 'admin',
        'controller' => 'session',
    ]
);

$route->beforeMatch(
    [
        new AjaxFilter(),
        'check'
    ]
);

最后,您可以使用beforeMatch方法(或事件)来检查这是否是一次 AJAX 请求。

<?php

use Phalcon\Di\DiInterface;
use Phalcon\Http\Request;
use Phalcon\Mvc\Router\Route;

$route = $router->add(
    '/login',
    [
        'module'     => 'admin',
        'controller' => 'session',
    ]
);

$route->beforeMatch(
    function ($uri, $route) {
        /**
         * @var string     $uri
         * @var Route       $route
         * @var DiInterface $this
         * @var Request     $request
         */
        $request = $this->getShared('request');

        return $request->isAjax();
    }
);

主机名

The Phalcon\Mvc\Router组件还允许主机名约束。这意味着特定的路由或一组路由仅在请求来源于特定主机名时才匹配。

<?php

$route = $router->add(
    '/admin/invoices/:action/:params',
    [
        'module'     => 'admin',
        'controller' => 'invoices',
        'action'     => 1,
        'params'     => 2,
    ]
);

$route->setHostName('dev.phalcon.ld');

主机名也可以作为正则表达式传入:

<?php

$route = $router->add(
    '/admin/invoices/:action/:params',
    [
        'module'     => 'admin',
        'controller' => 'invoices',
        'action'     => 1,
        'params'     => 2,
    ]
);

$route->setHostName('([a-z]+).phalcon.ld');

在使用路由组时,您可以为该组中的每个路由设置主机名约束。

<?php

use Phalcon\Mvc\Router\Group;

$invoices = new Group(
    [
        'module'     => 'admin',
        'controller' => 'invoices',
    ]
);

$invoices->setHostName('dev.phalcon.ld');
$invoices->setPrefix('/invoices');

$invoices->add(
    '/',
    [
        'action' => 'index',
    ]
);

$invoices->add(
    '/list',
    [
        'action' => 'list',
    ]
);

$invoices->add(
    '/view/{id}',
    [
        'action' => 'view',
    ]
);

$router->mount($invoices);

测试

该组件没有任何依赖项。因此您可以创建单元测试来测试您的路由。

<?php

use Phalcon\Mvc\Router;

$testRoutes = [
    '/',
    '/index',
    '/index/index',
    '/index/test',
    '/products',
    '/products/index/',
    '/products/show/101',
];

$router = new Router();

foreach ($testRoutes as $testRoute) {
    // Handle the route
    $router->handle($testRoute);

    echo 'Testing ', $testRoute, '<br>';

    // Check if some route was matched
    if ($router->wasMatched()) {
        echo 'Controller: ', $router->getControllerName(), '<br>';
        echo 'Action: ', $router->getActionName(), '<br>';
    } else {
        echo "The route wasn't matched by any route<br>";
    }

    echo '<br>';
}

事件

与其他 Phalcon 组件类似,Phalcon\Mvc\Router在存在事件管理器时也会触发事件。可用的事件包括:

事件
afterCheckRoutes 检查完所有路由之后触发
beforeCheckRoute 检查某个路由之前触发
beforeCheckRoutes 检查所有已加载路由之前触发
beforeMount 挂载新路由之前触发
matchedRoute 当路由匹配时触发
notMatchedRoute 当路由不匹配时触发

注解

该组件提供了一个与注解服务集成的变体。使用这种策略,您可以直接在控制器中编写路由,而不必将其添加到路由器组件中。

<?php

use Phalcon\Mvc\Router\Annotations;

$container['router'] = function () {
    $router = new Annotations(false);

    $router->addResource('Invoices', '/admin/invoices');

    return $router;
};
在上面的例子中,我们使用了Phalcon\Mvc\Router\Annotations组件来设置我们的路由。我们传递false以移除默认行为。之后,我们指示组件从InvoicesController如果 URI 匹配/admin/invoices.

The InvoicesController将需要具有以下实现:

<?php

/**
 * @RoutePrefix('/admin/invoices')
 */
class InvoicesController
{
    /**
     * @Get(
     *     '/'
     * )
     */
    public function indexAction()
    {

    }

    /**
     * @Get(
     *     '/edit/{id:[0-9]+}',
     *     name='invoice-edit'
     * )
     */
    public function editAction($id)
    {

    }

    /**
     * @Route(
     *     '/save',
     *     methods={'POST', 'PUT'},
     *     name='invoice-save'
     * )
     */
    public function saveAction()
    {

    }

    /**
     * @Route(
     *     '/delete/{id:[0-9]+}',
     *     methods='DELETE',
     *     converters={
     *         id='MyConverters::checkId'
     *     }
     * )
     */
    public function deleteAction($id)
    {

    }
}

只有标记了有效注解的方法才会被用作路由。可用的注解包括:

注解 描述 使用
Delete 限制 HTTP 方法为DELETE @Delete('/invoices/delete/{id}')
Get 限制 HTTP 方法为GET @Get('/invoices/search')
Options 限制 HTTP 方法为OPTIONS @Option('/invoices/info')
Post 限制 HTTP 方法为POST @Post('/invoices/save')
Put 限制 HTTP 方法为PUT @Put('/invoices/save')
Route 标记一个方法为路由。必须放置在方法的文档块中 @Route('/invoices/show')
RoutePrefix 前缀,将被添加到每个路由 URI 的前面。必须放置在类的文档块中 @RoutePrefix('/invoices')

对于添加路由的注解,支持以下参数:

名称 描述 使用
converters 参数的转换器哈希表 @Route('/posts/{id}/{slug}', converter={id='MyConverter::getId'})
methods 允许的一个或多个 HTTP 方法 @Route('/api/products', methods={'GET', 'POST'})
name 路由的名称 @Route('/api/products', name='get-products')
paths 路由的路径数组 @Route('/invoices/view/{id}/{slug}', paths={module='backend'})

如果您在应用中使用了模块,最好使用addModuleResource()方法:

<?php

use Phalcon\Mvc\Router\Annotations;

$container['router'] = function () {
    $router = new Annotations(false);

    $router->addModuleResource(
        'admin', 
        'Invoices', 
        '/admin/invoices'
    );

    return $router;
};
在上面的例子中,我们将从Admin\Controllers\InvoicesController如果 URI 以/admin/invoices.

路由器还理解前缀,以确保路由能够尽可能快地解析。例如对于以下路由:

/clients/{clientId:[0-9]+}/
/clients/{clientId:[0-9]+}/robots
/clients/{clientId:[0-9]+}/parts

只有/clients前缀可以在所有控制器中使用,从而加快查找速度。

依赖注入

您可以在容器设置期间注册路由器组件,使其在控制器或任何其他继承自Phalcon\Di\Injectable组件定义的。

您可以在您的引导文件中(例如index.phpapp/config/services.php如果您使用了Phalcon 开发者工具)。

<?php

$container->set(
    'router',
    function () {
        require __DIR__ . '/app/config/routes.php';

        return $router;
    }
);

您需要创建app/config/routes.php并添加路由器初始化代码:

<?php

use Phalcon\Mvc\Router;

$router = new Router();

$router->add(
    '/login',
    [
        'controller' => 'login',
        'action'     => 'index',
    ]
);

$router->add(
    '/invoices/:action',
    [
        'controller' => 'invoices',
        'action'     => 1,
    ]
);

return $router;

自定义

您可以通过实现提供的接口来创建自己的组件:-Phalcon\Mvc\Router\GroupInterface - Phalcon\Mvc\Router\RouteInterface - Phalcon\Mvc\RouterInterface

示例

以下是自定义路由的示例:

<?php

// '/system/admin/a/edit/7001'
$router->add(
    '/system/:controller/a/:action/:params',
    [
        'controller' => 1,
        'action'     => 2,
        'params'     => 3,
    ]
);

// '/en/news'
$router->add(
    '/([a-z]{2})/:controller',
    [
        'controller' => 2,
        'action'     => 'index',
        'language'   => 1,
    ]
);

// '/en/news'
$router->add(
    '/{language:[a-z]{2}}/:controller',
    [
        'controller' => 2,
        'action'     => 'index',
    ]
);

// '/admin/posts/edit/100'
$router->add(
    '/admin/:controller/:action/:int',
    [
        'controller' => 1,
        'action'     => 2,
        'id'         => 3,
    ]
);

// '/posts/2015/02/some-cool-content'
$router->add(
    '/posts/([0-9]{4})/([0-9]{2})/([a-z\-]+)',
    [
        'controller' => 'posts',
        'action'     => 'show',
        'year'       => 1,
        'month'      => 2,
        'title'      => 3,
    ]
);

// '/manual/en/translate.adapter.html'
$router->add(
    '/manual/([a-z]{2})/([a-z\.]+)\.html',
    [
        'controller' => 'manual',
        'action'     => 'show',
        'language'   => 1,
        'file'       => 2,
    ]
);

// /feed/fr/hot-news.atom
$router->add(
    '/feed/{lang:[a-z]+}/{blog:[a-z\-]+}\.{type:[a-z\-]+}',
    'Feed::get'
);

// /api/v1/users/peter.json
$router->add(
    '/api/(v1|v2)/{method:[a-z]+}/{param:[a-z]+}\.(json|xml)',
    [
        'controller' => 'api',
        'version'    => 1,
        'format'     => 4,
    ]
);

注意

在允许控制器和命名空间中使用正则表达式时,请小心处理字符。这些字符将成为类名,进而会与文件系统交互。因此,攻击者可能会访问未经授权的文件。一个安全的正则表达式是:/([a-zA-Z0-9\_\-]+)

无噪 Logo
无噪文档
25 年 6 月翻译
版本号 5.9
文档源↗