dcp / router
提供可扩展的事件驱动、MVC和REST路由器
Requires
- evenement/evenement: 2.0.*
Requires (Dev)
- phpunit/phpunit: 3.7.*
- satooshi/php-coveralls: dev-master
This package is not auto-updated.
Last update: 2024-09-24 06:06:18 UTC
README
#DCP-Router DCP-Router提供可扩展的事件驱动、MVC和REST路由器。
项目的目标是始终追求简洁、简单、可扩展和可测试。
入门
安装此包最简单、最推荐的方式是通过composer。
只需在您的项目中创建一个composer.json文件,并添加以下行
{ "require": { "dcp/router": "1.0.*" } }
然后,运行composer命令安装DCP-Router
$ composer install
或者,您可以克隆仓库并手动安装包。
基本用法
创建MVC或REST路由器
您需要做的第一件事是实例化路由器。您可以选择MVC或REST路由器。
use DCP\Router; $mvcRouter = new Router\MvcRouter(); $restRouter = new Router\RestRouter();
路由分配
一旦您创建了路由器,您就可以立即分配路由,而无需其他配置。
默认情况下,路由器将在根命名空间中查找控制器类。这是可配置的,在README的其他部分有所体现。
例如,如果您选择MVC路由器来分配路由
use DCP\Router\MvcRouter; class TestController { public function indexAction($arg = null) { echo __METHOD__ . ', ' . $arg; } } class HomeController { public function testAction() { echo __METHOD__; } } $router = new MvcRouter(); $router->dispatch('/test/index/hello'); // This will output "TestController::indexAction, hello" $router->dispatch('/home/test'); // This will output "HomeController::testAction"
或者,如果您选择REST路由器来分配路由
use DCP\Router\RestRouter; class UsersController { public function get() { echo __METHOD__; } public function post($arg = null) { echo __METHOD__ . ', ' . $arg; } } $router = new RestRouter(); $router->dispatch('/users/hello', 'post'); // This will output "UsersController::post, hello" $router->dispatch('/users', 'get'); // This will output "UsersController::get"
默认路由
当没有URL或部分URL呈现给路由器时,它将假设一个默认路由以避免抛出NotFound异常。
在MVC路由器的情况下,如果没有呈现路由,它将假设一个index控制器和一个index动作。如果指定了控制器但没有动作,它将假设调用index动作。
use DCP\Router\MvcRouter; class IndexController { public function indexAction() { echo __METHOD__; } } class HomeController { public function indexAction() { echo __METHOD__; } } $router = new MvcRouter(); $router->dispatch('/'); // This will output "IndexController::indexAction" $router->dispatch('/home'); // This will output "HomeController::indexAction"
在REST路由器的情况下,如果没有呈现路由,它将假设一个index控制器和一个GET方法。如果指定了控制器但没有HTTP方法,它将假设调用GET方法。
use DCP\Router\RestRouter; class IndexController { public function get() { echo __METHOD__; } } class HomeController { public function get() { echo __METHOD__; } public function post() { echo __METHOD__; } } $router = new RestRouter(); $router->dispatch('/'); // This will output "IndexController::get" $router->dispatch('/home'); // This will output "HomeController::get" $router->dispatch('/home', 'post'); // This will output "HomeController::post"
未找到错误
当路由器无法找到指定的资源时,它将抛出NotFoundException,允许您显示一个404页面(如果需要的话)。
use DCP\Router\MvcRouter; $router = new MvcRouter(); // RestRouter can be used here, too. try { $router->dispatch('/home'); } catch (NotFoundException $e) { echo 'Could not find /home!!'; }
控制器命名空间前缀
当您的应用程序足够复杂,需要使用命名空间进行结构化时,您可以开始为路由器设置命名空间前缀。路由器将在您指定的任何命名空间中查找控制器。
// App/Controller/TestController.php namespace App\Controller; class TestController { public function helloAction() { echo 'Hello, world!'; } }
// index.php use DCP\Router\MvcRouter; $router = new MvcRouter(); $router->setControllerPrefix('App\Controller'); $router->dispatch('/test/hello'); // This will output "Hello, world!"
路由层次结构
DCP-Router让您能够创建具有自己的URL前缀的独立站点区域,例如位于/admin下的管理站点部分。
为了便于这种功能,项目依赖于分层路由,其中路由器将在看到已知前缀时将URL传递给其他路由器实例。
例如,我们将创建一个只能通过/admin URL前缀访问的控制器。
// App/Admin/Controller/TestController.php namespace App\Admin\Controller; class TestController { public function helloAction() { echo 'Hello, world!'; } }
然后,我们将创建一个AdminRouter类来便于将路由到站点的/App/Admin/Controller命名空间。
// App/Admin/AdminRouter.php namespace App\Admin; use DCP\Router\MvcRouter; class AdminRouter extends MvcRouter { public function __construct() { parent::__construct(); $this->setControllerPrefix('App\Admin\Controller'); } }
最后,我们实例化一个路由器,并告诉它任何位于/admin URL前缀下的内容都应该由AdminRouter处理。
// index.php use DCP\Router\MvcRouter; $router = new MvcRouter(); $router->setComponents([ 'admin' => 'App\Admin\AdminRouter' ]); $router->dispatch('/admin/test/hello'); // This will output "Hello, world!"
当路由器被告知路由到/admin/test/hello时,它将看到URL的第一部分是admin。由于已注册了具有admin键的组件,路由器将分配路由的/test/hello部分给AdminRouter,然后最终调用TestController#helloAction()。
详细用法
事件系统
DCP-Router的核心采用了Evenement,并为路由过程中的每个步骤都提供了事件。这允许您在过程中的任何一点进行连接,并在需要时执行自定义逻辑。
总共有12个事件,其中6个在控制器被分发时调用,另外6个在次要路由器被分发时调用。事件按照列表中的顺序调用它们各自区域的事件。
控制器事件
ControllerEvents::CREATING
在路由器解析要分发的控制器的完全限定类名时发出。- 此事件可用于自定义控制器解析逻辑。
ControllerEvents::CREATE
在路由器实例化控制器时发出。- 此事件可用于自定义类创建逻辑。
ControllerEvents::CREATED
在路由器实例化控制器后发出。ControllerEvents::DISPATCHING
在路由器解析要调用的控制器上的方法名称时发出。- 此事件可用于自定义控制器方法解析逻辑。
ControllerEvents::DISPATCH
在路由器调用解析后的控制器方法时发出。- 此事件可用于自定义控制器动作分发逻辑。
ControllerEvents::DISPATCHED
在路由器调用解析后的控制器方法后发出。
组件事件
ComponentEvents::CREATING
在路由器解析要分发的组件路由器的完全限定类名时发出。默认情况下,它是*Router#setComponents()
调用中指定的类名。ComponentEvents::CREATE
在路由器实例化组件路由器时发出。- 此事件可用于自定义类创建逻辑。
ComponentEvents::CREATED
在路由器实例化组件路由器后发出。ComponentEvents::DISPATCHING
在路由器准备将控制权传递给组件路由器时发出。ComponentEvents::DISPATCH
在路由器将控制权传递给组件路由器时发出。- 此事件可用于提供自定义组件分发逻辑。
ComponentEvents::DISPATCHED
在路由器将控制权传递给组件路由器后,以及组件路由器完成后发出。
要连接到事件,您可以简单地为事件附加一个监听器。当路由器进入路由的特定阶段时,它将被调用。
use DCP\Router\MvcRouter; use DCP\Router\ControllerEvents; use DCP\Router\Event\CreatingEvent; class TestControllerHi { public function indexAction() { echo 'Hello!!' } } $router = new MvcRouter(); $router->on(ControllerEvents::CREATING, function (CreatingEvent $event) { $event->setClass($event->getClass() . 'Hi'); }); $router->dispatch('/test'); // This will output "Hello!!"
与依赖注入容器的耦合
事件系统的一个重要方面是它允许轻松集成到各种依赖注入容器中。
ControllerEvents::CREATE
和ComponentEvents::CREATE
事件专门用于实例化一个类,因此它们可以被覆盖以从DI容器中提取实例。
use DCP\Router\MvcRouter; use DCP\Router\ControllerEvents; use DCP\Router\ComponentEvents; use DCP\Di\Container; use DCP\Di\ContainerAwareInterface; class DiMvcRouter extends MvcRouter implements ContainerAwareInterface { protected $container; public function setContainer(Container $container) { $this->container = $container; } public function __construct() { parent::__construct(); $createCallback = function (CreateEvent $event) { $container = $this->container; $class = $event->getClass(); $event->setInstance($container->get($class)); }; $this->removeAllListeners(ControllerEvents::CREATE); $this->on(ControllerEvents::CREATE, $createCallback); $this->removeAllListeners(ComponentEvents::CREATE); $this->on(ComponentEvents::CREATE, $createCallback); } }
贡献
如果您想为DCP-Router做出贡献,您可以通过以下两种方式之一进行
- 提交您发现的错误或可以改进项目的功能。
- 分支存储库,并提交拉取请求。
测试
DCP-Router使用PHPUnit 3.7.x进行自动化测试。
代码库的所有更改都伴随着单元测试。