Application


Application - 图1

Creating a MVC Application

All the hard work behind orchestrating the operation of MVC in Phalcon is normally done by Phalcon\Mvc\Application. This component encapsulates all the complex operations required in the background, instantiating every component needed and integrating it with the project, to allow the MVC pattern to operate as desired.

The following bootstrap code is typical for a Phalcon application:

  1. <?php
  2. use Phalcon\Mvc\Application;
  3. // Register autoloaders
  4. // ...
  5. // Register services
  6. // ...
  7. // Handle the request
  8. $application = new Application($di);
  9. try {
  10. $response = $application->handle(
  11. $_SERVER["REQUEST_URI"]
  12. );
  13. $response->send();
  14. } catch (\Exception $e) {
  15. echo 'Exception: ', $e->getMessage();
  16. }

The core of all the work of the controller occurs when handle() is invoked:

  1. <?php
  2. $response = $application->handle(
  3. $_SERVER["REQUEST_URI"]
  4. );

Manual bootstrapping

If you do not wish to use Phalcon\Mvc\Application, the code above can be changed as follows:

  1. <?php
  2. // Get the 'router' service
  3. $router = $di['router'];
  4. $router->handle(
  5. $_SERVER["REQUEST_URI"]
  6. );
  7. $view = $di['view'];
  8. $dispatcher = $di['dispatcher'];
  9. // Pass the processed router parameters to the dispatcher
  10. $dispatcher->setControllerName(
  11. $router->getControllerName()
  12. );
  13. $dispatcher->setActionName(
  14. $router->getActionName()
  15. );
  16. $dispatcher->setParams(
  17. $router->getParams()
  18. );
  19. // Start the view
  20. $view->start();
  21. // Dispatch the request
  22. $dispatcher->dispatch();
  23. // Render the related views
  24. $view->render(
  25. $dispatcher->getControllerName(),
  26. $dispatcher->getActionName(),
  27. $dispatcher->getParams()
  28. );
  29. // Finish the view
  30. $view->finish();
  31. $response = $di['response'];
  32. // Pass the output of the view to the response
  33. $response->setContent(
  34. $view->getContent()
  35. );
  36. // Send the response
  37. $response->send();

The following replacement of Phalcon\Mvc\Application lacks of a view component making it suitable for Rest APIs:

  1. <?php
  2. use Phalcon\Http\ResponseInterface;
  3. // Get the 'router' service
  4. $router = $di['router'];
  5. $router->handle(
  6. $_SERVER["REQUEST_URI"]
  7. );
  8. $dispatcher = $di['dispatcher'];
  9. // Pass the processed router parameters to the dispatcher
  10. $dispatcher->setControllerName(
  11. $router->getControllerName()
  12. );
  13. $dispatcher->setActionName(
  14. $router->getActionName()
  15. );
  16. $dispatcher->setParams(
  17. $router->getParams()
  18. );
  19. // Dispatch the request
  20. $dispatcher->dispatch();
  21. // Get the returned value by the last executed action
  22. $response = $dispatcher->getReturnedValue();
  23. // Check if the action returned is a 'response' object
  24. if ($response instanceof ResponseInterface) {
  25. // Send the response
  26. $response->send();
  27. }

Yet another alternative that catch exceptions produced in the dispatcher forwarding to other actions consequently:

  1. <?php
  2. use Phalcon\Http\ResponseInterface;
  3. // Get the 'router' service
  4. $router = $di['router'];
  5. $router->handle(
  6. $_SERVER["REQUEST_URI"]
  7. );
  8. $dispatcher = $di['dispatcher'];
  9. // Pass the processed router parameters to the dispatcher
  10. $dispatcher->setControllerName(
  11. $router->getControllerName()
  12. );
  13. $dispatcher->setActionName(
  14. $router->getActionName()
  15. );
  16. $dispatcher->setParams(
  17. $router->getParams()
  18. );
  19. try {
  20. // Dispatch the request
  21. $dispatcher->dispatch();
  22. } catch (Exception $e) {
  23. // An exception has occurred, dispatch some controller/action aimed for that
  24. // Pass the processed router parameters to the dispatcher
  25. $dispatcher->setControllerName('errors');
  26. $dispatcher->setActionName('action503');
  27. // Dispatch the request
  28. $dispatcher->dispatch();
  29. }
  30. // Get the returned value by the last executed action
  31. $response = $dispatcher->getReturnedValue();
  32. // Check if the action returned is a 'response' object
  33. if ($response instanceof ResponseInterface) {
  34. // Send the response
  35. $response->send();
  36. }

Although the above implementations are a lot more verbose than the code needed while using Phalcon\Mvc\Application, offers an alternative in bootstrapping your application. Depending on your needs, you might want to have full control of what should be instantiated or not, or replace certain components with those of your own to extend the default functionality.

Single or Multi Module Applications

With this component you can run various types of MVC structures:

Single Module

Single MVC applications consist of one module only. Namespaces can be used but are not necessary. An application like this would have the following file structure:

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

If namespaces are not used, the following bootstrap file could be used to orchestrate the MVC flow:

  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. // Registering the view component
  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. $_SERVER["REQUEST_URI"]
  28. );
  29. $response->send();
  30. } catch (\Exception $e) {
  31. echo $e->getMessage();
  32. }

If namespaces are used, the following bootstrap can be used:

  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. // Use autoloading with namespaces prefixes
  9. $loader->registerNamespaces(
  10. [
  11. 'Single\Controllers' => '../apps/controllers/',
  12. 'Single\Models' => '../apps/models/',
  13. ]
  14. );
  15. $loader->register();
  16. $di = new FactoryDefault();
  17. // Register the default dispatcher's namespace for controllers
  18. $di->set(
  19. 'dispatcher',
  20. function () {
  21. $dispatcher = new Dispatcher();
  22. $dispatcher->setDefaultNamespace('Single\Controllers');
  23. return $dispatcher;
  24. }
  25. );
  26. // Register the view component
  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. $_SERVER["REQUEST_URI"]
  39. );
  40. $response->send();
  41. } catch (\Exception $e) {
  42. echo $e->getMessage();
  43. }

Multi Module

A multi-module application uses the same document root for more than one module. In this case the following file structure can be used:

  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/

Each directory in apps/ have its own MVC structure. A Module.php is present to configure specific settings of each module like autoloaders or custom services:

  1. <?php
  2. namespace Multiple\Backend;
  3. use Phalcon\Loader;
  4. use Phalcon\Mvc\View;
  5. use Phalcon\Di\DiInterface;
  6. use Phalcon\Mvc\Dispatcher;
  7. use Phalcon\Mvc\ModuleDefinitionInterface;
  8. class Module implements ModuleDefinitionInterface
  9. {
  10. /**
  11. * Register a specific autoloader for the module
  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. * Register specific services for the module
  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. }

A special bootstrap file is required to load a multi-module MVC architecture:

  1. <?php
  2. use Phalcon\Mvc\Router;
  3. use Phalcon\Mvc\Application;
  4. use Phalcon\Di\FactoryDefault;
  5. $di = new FactoryDefault();
  6. // Specify routes for modules
  7. $di->set(
  8. 'router',
  9. function () {
  10. $router = new Router();
  11. $router->setDefaultModule('frontend');
  12. $router->add(
  13. '/login',
  14. [
  15. 'module' => 'backend',
  16. 'controller' => 'login',
  17. 'action' => 'index',
  18. ]
  19. );
  20. $router->add(
  21. '/admin/products/:action',
  22. [
  23. 'module' => 'backend',
  24. 'controller' => 'products',
  25. 'action' => 1,
  26. ]
  27. );
  28. $router->add(
  29. '/products/:action',
  30. [
  31. 'controller' => 'products',
  32. 'action' => 1,
  33. ]
  34. );
  35. return $router;
  36. }
  37. );
  38. // Create an application
  39. $application = new Application($di);
  40. // Register the installed modules
  41. $application->registerModules(
  42. [
  43. 'frontend' => [
  44. 'className' => \Multiple\Frontend\Module::class,
  45. 'path' => '../apps/frontend/Module.php',
  46. ],
  47. 'backend' => [
  48. 'className' => \Multiple\Backend\Module::class,
  49. 'path' => '../apps/backend/Module.php',
  50. ]
  51. ]
  52. );
  53. try {
  54. // Handle the request
  55. $response = $application->handle(
  56. $_SERVER["REQUEST_URI"]
  57. );
  58. $response->send();
  59. } catch (\Exception $e) {
  60. echo $e->getMessage();
  61. }

If you want to maintain the module configuration in the bootstrap file you can use an anonymous function to register the module:

  1. <?php
  2. use Phalcon\Mvc\View;
  3. // Creating a view component
  4. $view = new View();
  5. // Set options to view component
  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. );

When Phalcon\Mvc\Application have modules registered, always is necessary that every matched route returns a valid module. Each registered module has an associated class offering functions to set the module itself up. Each module class definition must implement two methods: registerAutoloaders() and registerServices(), they will be called by Phalcon\Mvc\Application according to the module to be executed.

Application Events

Phalcon\Mvc\Application is able to send events to the EventsManager (if it is present). Events are triggered using the type application. The following events are supported:

Event NameTriggered
bootExecuted when the application handles its first request
beforeStartModuleBefore initialize a module, only when modules are registered
afterStartModuleAfter initialize a module, only when modules are registered
beforeHandleRequestBefore execute the dispatch loop
afterHandleRequestAfter execute the dispatch loop

The following example demonstrates how to attach listeners to this component:

  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

  • MVC examples on GitHub

  • This component encapsulates all the complex operations behind instantiating

  • every component needed and integrating it with the rest to allow the MVC
  • pattern to operate as desired.public function __construct( container = null)

  • Phalcon\AbstractApplication constructorpublic function getDefaultModule() -> string

  • Returns the default module namepublic function getEventsManager() ->
  • Returns the internal event managerpublic function getModule(string! name) -> array | object
  • Gets the module definition registered in the application via module namepublic function getModules() -> array
  • Return the modules registered in the applicationpublic function registerModules(array modules, bool merge = false) ->
  • Register an array of modules present in the application*
  • ```php
  • $this->registerModules(
  • [
  • “frontend” => [
  • “className” => \Multiple\Frontend\Module::class,
  • “path” => “../apps/frontend/Module.php”,
  • ],
  • “backend” => [
  • “className” => \Multiple\Backend\Module::class,
  • “path” => “../apps/backend/Module.php”,
  • ],
  • ]
  • );
  • ```*/public function setDefaultModule(string! defaultModule) ->
  • Sets the module name to be used if the router doesn’t return a valid modulepublic function setEventsManager( eventsManager) -> void
  • Sets the events managerpublic function handle(string! uri) -> | bool
  • Handles a MVC requestpublic function sendCookiesOnHandleRequest(bool sendCookies) ->
  • Enables or disables sending cookies by each request handlingpublic function sendHeadersOnHandleRequest(bool sendHeaders) ->
  • Enables or disables sending headers by each request handlingpublic function useImplicitView(bool implicitView) ->
  • By default. The view is implicitly buffering all the output You can full disable the view component using this method