MVC 应用(MVC Applications)

在Phalcon,策划MVC操作背后的全部困难工作通常都可以 通过 Phalcon\Mvc\Application 做到。这个组件封装了全部后端所需要的复杂 操作,实例化每一个需要用到的组件并与项目整合在一起,从而使得MVC模式可以如期地运行。

单模块或多模块应用(Single or Multi Module Applications)

通过这个组件,你可以运行各式各样的MVC结构:

单模块(Single Module)

单一的MVC应用仅仅包含了一个模块。可以使用命名空间,但不是必需的。 这样类型的应用可能会有以下文件目录结构:

  1. single/
  2. app/
  3. controllers/
  4. models/
  5. views/
  6. public/
  7. css/
  8. img/
  9. js/

如果未使用命名空间,以下的启动文件可用于编排MVC工作流:

  1. <?php
  2. use Phalcon\Loader;
  3. use Phalcon\Mvc\View;
  4. use Phalcon\Mvc\Application;
  5. use Phalcon\Di\FactoryDefault;
  6. $loader = new Loader();
  7. $loader->registerDirs(
  8. [
  9. "../apps/controllers/",
  10. "../apps/models/",
  11. ]
  12. );
  13. $loader->register();
  14. $di = new FactoryDefault();
  15. // 注册视图组件
  16. $di->set(
  17. "view",
  18. function () {
  19. $view = new View();
  20. $view->setViewsDir("../apps/views/");
  21. return $view;
  22. }
  23. );
  24. $application = new Application($di);
  25. try {
  26. $response = $application->handle();
  27. $response->send();
  28. } catch (\Exception $e) {
  29. echo $e->getMessage();
  30. }

如果使用了命名空间,则可以使用以下启动文件(译者注:主要区别在于使用$loader的方式):

  1. <?php
  2. use Phalcon\Loader;
  3. use Phalcon\Mvc\View;
  4. use Phalcon\Mvc\Dispatcher;
  5. use Phalcon\Mvc\Application;
  6. use Phalcon\Di\FactoryDefault;
  7. $loader = new Loader();
  8. // 根据命名空间前缀加载
  9. $loader->registerNamespaces(
  10. [
  11. "Single\\Controllers" => "../apps/controllers/",
  12. "Single\\Models" => "../apps/models/",
  13. ]
  14. );
  15. $loader->register();
  16. $di = new FactoryDefault();
  17. // 注册调度器,并设置控制器的默认命名空间
  18. $di->set(
  19. "dispatcher",
  20. function () {
  21. $dispatcher = new Dispatcher();
  22. $dispatcher->setDefaultNamespace("Single\\Controllers");
  23. return $dispatcher;
  24. }
  25. );
  26. // 注册视图组件
  27. $di->set(
  28. "view",
  29. function () {
  30. $view = new View();
  31. $view->setViewsDir("../apps/views/");
  32. return $view;
  33. }
  34. );
  35. $application = new Application($di);
  36. try {
  37. $response = $application->handle();
  38. $response->send();
  39. } catch (\Exception $e) {
  40. echo $e->getMessage();
  41. }

多模块(Multi Module)

多模块的应用使用了相同的文档根目录但拥有多个模块。在这种情况下,可以使用以下的文件目录结构:

  1. multiple/
  2. apps/
  3. frontend/
  4. controllers/
  5. models/
  6. views/
  7. Module.php
  8. backend/
  9. controllers/
  10. models/
  11. views/
  12. Module.php
  13. public/
  14. css/
  15. img/
  16. js/

在apps/下的每一个目录都有自己的MVC结构。Module.php文件代表了各个模块不同的配置,如自动加载器和自定义服务:

  1. <?php
  2. namespace Multiple\Backend;
  3. use Phalcon\Loader;
  4. use Phalcon\Mvc\View;
  5. use Phalcon\DiInterface;
  6. use Phalcon\Mvc\Dispatcher;
  7. use Phalcon\Mvc\ModuleDefinitionInterface;
  8. class Module implements ModuleDefinitionInterface
  9. {
  10. /**
  11. * 注册自定义加载器
  12. */
  13. public function registerAutoloaders(DiInterface $di = null)
  14. {
  15. $loader = new Loader();
  16. $loader->registerNamespaces(
  17. [
  18. "Multiple\\Backend\\Controllers" => "../apps/backend/controllers/",
  19. "Multiple\\Backend\\Models" => "../apps/backend/models/",
  20. ]
  21. );
  22. $loader->register();
  23. }
  24. /**
  25. * 注册自定义服务
  26. */
  27. public function registerServices(DiInterface $di)
  28. {
  29. // Registering a dispatcher
  30. $di->set(
  31. "dispatcher",
  32. function () {
  33. $dispatcher = new Dispatcher();
  34. $dispatcher->setDefaultNamespace("Multiple\\Backend\\Controllers");
  35. return $dispatcher;
  36. }
  37. );
  38. // Registering the view component
  39. $di->set(
  40. "view",
  41. function () {
  42. $view = new View();
  43. $view->setViewsDir("../apps/backend/views/");
  44. return $view;
  45. }
  46. );
  47. }
  48. }

还需要一个指定的启动文件来加载多模块的MVC架构:

  1. <?php
  2. use Phalcon\Mvc\Router;
  3. use Phalcon\Mvc\Application;
  4. use Phalcon\Di\FactoryDefault;
  5. $di = new FactoryDefault();
  6. // 自定义路由
  7. // More information how to set the router up https://docs.phalconphp.com/zh/latest/reference/routing.html
  8. $di->set(
  9. "router",
  10. function () {
  11. $router = new Router();
  12. $router->setDefaultModule("frontend");
  13. $router->add(
  14. "/login",
  15. [
  16. "module" => "backend",
  17. "controller" => "login",
  18. "action" => "index",
  19. ]
  20. );
  21. $router->add(
  22. "/admin/products/:action",
  23. [
  24. "module" => "backend",
  25. "controller" => "products",
  26. "action" => 1,
  27. ]
  28. );
  29. $router->add(
  30. "/products/:action",
  31. [
  32. "controller" => "products",
  33. "action" => 1,
  34. ]
  35. );
  36. return $router;
  37. }
  38. );
  39. // 创建应用
  40. $application = new Application($di);
  41. // 注册模块
  42. $application->registerModules(
  43. [
  44. "frontend" => [
  45. "className" => "Multiple\\Frontend\\Module",
  46. "path" => "../apps/frontend/Module.php",
  47. ],
  48. "backend" => [
  49. "className" => "Multiple\\Backend\\Module",
  50. "path" => "../apps/backend/Module.php",
  51. ]
  52. ]
  53. );
  54. // 处理请求
  55. $response = $application->handle();
  56. $response->send();
  57. } catch (\Exception $e) {
  58. echo $e->getMessage();
  59. }

如果你想在启动文件保持模块的配置,你可以使用匿名函数来注册对应的模块:

  1. <?php
  2. use Phalcon\Mvc\View;
  3. // 创建视图组件
  4. $view = new View();
  5. // 设置视图组件相关选项
  6. // ...
  7. // Register the installed modules
  8. $application->registerModules(
  9. [
  10. "frontend" => function ($di) use ($view) {
  11. $di->setShared(
  12. "view",
  13. function () use ($view) {
  14. $view->setViewsDir("../apps/frontend/views/");
  15. return $view;
  16. }
  17. );
  18. },
  19. "backend" => function ($di) use ($view) {
  20. $di->setShared(
  21. "view",
  22. function () use ($view) {
  23. $view->setViewsDir("../apps/backend/views/");
  24. return $view;
  25. }
  26. );
  27. }
  28. ]
  29. );

Phalcon\Mvc\Application 有多个模块注册时,通常 每个都是需要的,以便每一个被匹配到的路由都能返回一个有效的模块。每个已经注册的模块都有一个相关的类来提供建立和启动自身的函数。 而每个模块定义的类都必须实现registerAutoloaders()和registerServices()这两个方法,这两个函数会在模块即被执行时被 Phalcon\Mvc\Application 调用。

应用事件(Application Events)

Phalcon\Mvc\Application 可以把事件发送到 EventsManager (如果它激活的话)。 事件将被当作”application”类型被消费掉。目前已支持的事件如下:

事件名称消费于
boot当应用处理它首个请求时被执行
beforeStartModule在初始化模块之前,仅当模块被注册时
afterStartModule在初始化模块之后,仅当模块被注册时
beforeHandleRequest在执行分发环前
afterHandleRequest在执行分发环后

以下示例演示了如何将侦听器绑定到组件:

  1. <?php
  2. use Phalcon\Events\Event;
  3. use Phalcon\Events\Manager as EventsManager;
  4. $eventsManager = new EventsManager();
  5. $application->setEventsManager($eventsManager);
  6. $eventsManager->attach(
  7. "application",
  8. function (Event $event, $application) {
  9. // ...
  10. }
  11. );

外部资源(External Resources)