🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # MVC 应用 在Phalcon中编排MVC操作的所有艰苦工作通常由`Phalcon\Mvc\Application`完成。该组件封装了后台所需的所有复杂操作,实例化了所需的每个组件并将其与项目集成,以允许MVC模式按需运行。 以下引导代码是Phalcon应用程序的典型代码: ```php <?php use Phalcon\Mvc\Application; // 注册自动加载器 // ... // 注册服务 // ... // 处理请求 $application = new Application($di); try { $response = $application->handle(); $response->send(); } catch (\Exception $e) { echo 'Exception: ', $e->getMessage(); } ``` 调用`handle()`时是控制器的所有工作的核心: ```php <?php $response = $application->handle(); ``` ## 手动引导 如果您不想使用`Phalcon\Mvc\Application`,可以按如下方式更改上面的代码: ```php <?php // 获取 router 服务 $router = $di['router']; $router->handle(); $view = $di['view']; $dispatcher = $di['dispatcher']; // 将已处理的路由器参数传递给调度程序 $dispatcher->setControllerName( $router->getControllerName() ); $dispatcher->setActionName( $router->getActionName() ); $dispatcher->setParams( $router->getParams() ); // 开始视图 $view->start(); // 发送请求 $dispatcher->dispatch(); // 呈现相关视图 $view->render( $dispatcher->getControllerName(), $dispatcher->getActionName(), $dispatcher->getParams() ); // 结束视图 $view->finish(); $response = $di['response']; // 将视图的输出传递给响应 $response->setContent( $view->getContent() ); // 发送响应 $response->send(); ``` 以下替换`Phalcon\Mvc\Application`缺少一个视图组件,使其适用于Rest API: ```php <?php use Phalcon\Http\ResponseInterface; // 获取 router 服务 $router = $di['router']; $router->handle(); $dispatcher = $di['dispatcher']; // 将已处理的路由器参数传递给调度程序 $dispatcher->setControllerName( $router->getControllerName() ); $dispatcher->setActionName( $router->getActionName() ); $dispatcher->setParams( $router->getParams() ); // 发送请求 $dispatcher->dispatch(); // 通过上次执行的操作获取返回值 $response = $dispatcher->getReturnedValue(); // 检查返回的操作是否为“响应”对象 if ($response instanceof ResponseInterface) { // 发送响应 $response->send(); } ``` 另一种替代方法是捕获调度员转发到其他操作时产生的异常: ```php <?php use Phalcon\Http\ResponseInterface; // 获取 router 服务 $router = $di['router']; $router->handle(); $dispatcher = $di['dispatcher']; // 将已处理的路由器参数传递给调度程序 $dispatcher->setControllerName( $router->getControllerName() ); $dispatcher->setActionName( $router->getActionName() ); $dispatcher->setParams( $router->getParams() ); try { // 发送请求 $dispatcher->dispatch(); } catch (Exception $e) { // 发生异常,发送一些针对此的控制器/操作 // 将已处理的路由器参数传递给调度程序 $dispatcher->setControllerName('errors'); $dispatcher->setActionName('action503'); // 发送请求 $dispatcher->dispatch(); } // 通过上次执行的操作获取返回值 $response = $dispatcher->getReturnedValue(); // 检查返回的操作是否为“响应”对象 if ($response instanceof ResponseInterface) { // 发送响应 $response->send(); } ``` 虽然上述实现比使用`Phalcon\Mvc\Application`时所需的代码要冗长得多,但在引导应用程序时提供了另一种选择。根据您的需要,您可能希望完全控制应该实例化的内容,或者使用您自己的组件替换某些组件以扩展默认功能。 ## 单/多模块应用 使用此组件,您可以运行各种类型的MVC结构: ### 单模块 单个MVC应用程序仅包含一个模块。可以使用命名空间,但不是必需的。像这样的应用程序将具有以下文件结构: ```php single/ app/ controllers/ models/ views/ public/ css/ img/ js/ ``` 如果未使用名称空间,则可以使用以下引导文件来编排MVC流: ```php <?php use Phalcon\Loader; use Phalcon\Mvc\View; use Phalcon\Mvc\Application; use Phalcon\Di\FactoryDefault; $loader = new Loader(); $loader->registerDirs( [ '../apps/controllers/', '../apps/models/', ] ); $loader->register(); $di = new FactoryDefault(); // 注册视图组件 $di->set( 'view', function () { $view = new View(); $view->setViewsDir('../apps/views/'); return $view; } ); $application = new Application($di); try { $response = $application->handle(); $response->send(); } catch (\Exception $e) { echo $e->getMessage(); } ``` 如果使用名称空间,可以使用以下引导程序: ```php <?php use Phalcon\Loader; use Phalcon\Mvc\View; use Phalcon\Mvc\Dispatcher; use Phalcon\Mvc\Application; use Phalcon\Di\FactoryDefault; $loader = new Loader(); // 使用带名称空间前缀的自动加载 $loader->registerNamespaces( [ 'Single\Controllers' => '../apps/controllers/', 'Single\Models' => '../apps/models/', ] ); $loader->register(); $di = new FactoryDefault(); // 为控制器注册默认调度程序的命名空间 $di->set( 'dispatcher', function () { $dispatcher = new Dispatcher(); $dispatcher->setDefaultNamespace('Single\Controllers'); return $dispatcher; } ); // 注册视图组件 $di->set( 'view', function () { $view = new View(); $view->setViewsDir('../apps/views/'); return $view; } ); $application = new Application($di); try { $response = $application->handle(); $response->send(); } catch (\Exception $e) { echo $e->getMessage(); } ``` ### 多模块 多模块应用程序对多个模块使用相同的文档根。在这种情况下,可以使用以下文件结构: ```php multiple/ apps/ frontend/ controllers/ models/ views/ Module.php backend/ controllers/ models/ views/ Module.php public/ css/ img/ js/ ``` apps/ 中的每个目录都有自己的MVC结构。`Module.php`用于配置每个模块的特定设置,如自动加载器或自定义服务: ```php <?php namespace Multiple\Backend; use Phalcon\Loader; use Phalcon\Mvc\View; use Phalcon\DiInterface; use Phalcon\Mvc\Dispatcher; use Phalcon\Mvc\ModuleDefinitionInterface; class Module implements ModuleDefinitionInterface { /** * 注册模块的特定自动加载 */ public function registerAutoloaders(DiInterface $di = null) { $loader = new Loader(); $loader->registerNamespaces( [ 'Multiple\Backend\Controllers' => '../apps/backend/controllers/', 'Multiple\Backend\Models' => '../apps/backend/models/', ] ); $loader->register(); } /** * 注册模块的特定服务 */ public function registerServices(DiInterface $di) { // 注册调度器 $di->set( 'dispatcher', function () { $dispatcher = new Dispatcher(); $dispatcher->setDefaultNamespace('Multiple\Backend\Controllers'); return $dispatcher; } ); // 注册视图组件 $di->set( 'view', function () { $view = new View(); $view->setViewsDir('../apps/backend/views/'); return $view; } ); } } ``` 加载多模块MVC架构需要特殊的引导程序文件: ```php <?php use Phalcon\Mvc\Router; use Phalcon\Mvc\Application; use Phalcon\Di\FactoryDefault; $di = new FactoryDefault(); // 指定模块的路由 $di->set( 'router', function () { $router = new Router(); $router->setDefaultModule('frontend'); $router->add( '/login', [ 'module' => 'backend', 'controller' => 'login', 'action' => 'index', ] ); $router->add( '/admin/products/:action', [ 'module' => 'backend', 'controller' => 'products', 'action' => 1, ] ); $router->add( '/products/:action', [ 'controller' => 'products', 'action' => 1, ] ); return $router; } ); // 创建一个应用 $application = new Application($di); // 注册已安装的模块 $application->registerModules( [ 'frontend' => [ 'className' => 'Multiple\Frontend\Module', 'path' => '../apps/frontend/Module.php', ], 'backend' => [ 'className' => 'Multiple\Backend\Module', 'path' => '../apps/backend/Module.php', ] ] ); try { // 处理请求 $response = $application->handle(); $response->send(); } catch (\Exception $e) { echo $e->getMessage(); } ``` 如果要在引导文件中维护模块配置,可以使用匿名函数注册模块: ```php <?php use Phalcon\Mvc\View; // 创建一个视图组件 $view = new View(); // 给视图组件设置参数 // ... // 注册已安装的模块 $application->registerModules( [ 'frontend' => function ($di) use ($view) { $di->setShared( 'view', function () use ($view) { $view->setViewsDir('../apps/frontend/views/'); return $view; } ); }, 'backend' => function ($di) use ($view) { $di->setShared( 'view', function () use ($view) { $view->setViewsDir('../apps/backend/views/'); return $view; } ); } ] ); ``` 当`Phalcon\Mvc\Application`注册了模块时,每个匹配的路由都必须返回一个有效的模块。每个注册的模块都有一个关联的类,它提供了设置模块本身的功能。每个模块类定义必须实现两个方法:`registerAutoloaders()`和`registerServices()`,它们将由`Phalcon\Mvc\Application`根据要执行的模块调用。 ## 应用事件 `Phalcon\Mvc\Application` 能够将事件发送到EventsManager(如果存在)。使用类型`application`触发事件。支持以下事件: | 事件名称 | Triggered | | --------------------- | -------------------------------- | | `boot` | 在应用程序处理其第一个请求时执行 | | `beforeStartModule` | 在初始化模块之前,仅在注册模块时 | | `afterStartModule` | 在初始化模块之后,仅在注册模块时 | | `beforeHandleRequest` | 在执行调度循环之前 | | `afterHandleRequest` | 在执行调度循环之后 | 以下示例演示如何将侦听器附加到此组件: ```php <?php use Phalcon\Events\Event; use Phalcon\Events\Manager as EventsManager; $eventsManager = new EventsManager(); $application->setEventsManager($eventsManager); $eventsManager->attach( 'application', function (Event $event, $application) { // ... } ); ``` ## 外部资源 * [MVC examples on Github](https://github.com/phalcon/mvc)