Dispatcher.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * MINZ - Copyright 2011 Marien Fressinaud
  5. * Sous licence AGPL3 <http://www.gnu.org/licenses/>
  6. */
  7. /**
  8. * The Dispatcher is in charge of initialising the Controller and execute the action as specified in the Request object.
  9. * It is a singleton.
  10. */
  11. final class Minz_Dispatcher {
  12. /**
  13. * Singleton
  14. */
  15. private static ?Minz_Dispatcher $instance = null;
  16. private static bool $needsReset;
  17. /** @var array<string,string> */
  18. private static array $registrations = [];
  19. private Minz_ActionController $controller;
  20. /**
  21. * Retrieves the Dispatcher instance
  22. */
  23. public static function getInstance(): Minz_Dispatcher {
  24. if (self::$instance === null) {
  25. self::$instance = new Minz_Dispatcher();
  26. }
  27. return self::$instance;
  28. }
  29. /**
  30. * Launches the controller specified in Request
  31. * Fills the Response body from the View
  32. * @throws Minz_Exception
  33. */
  34. public function run(): void {
  35. do {
  36. self::$needsReset = false;
  37. try {
  38. $this->createController(Minz_Request::controllerName());
  39. $this->controller->init();
  40. $this->controller->firstAction();
  41. if (!self::$needsReset) {
  42. $this->launchAction(
  43. Minz_Request::actionName()
  44. . 'Action'
  45. );
  46. }
  47. $this->controller->lastAction();
  48. if (!self::$needsReset) {
  49. $this->controller->declareCspHeader();
  50. $this->controller->view()->build();
  51. }
  52. } catch (Minz_Exception $e) {
  53. throw $e;
  54. }
  55. } while (self::$needsReset);
  56. }
  57. /**
  58. * Informs the controller that it must restart because the request has been modified
  59. */
  60. public static function reset(): void {
  61. self::$needsReset = true;
  62. }
  63. /**
  64. * Instantiates the Controller
  65. * @param string $base_name the name of the controller to instantiate
  66. * @throws Minz_ControllerNotExistException the controller does not exist
  67. * @throws Minz_ControllerNotActionControllerException controller is not an instance of ActionController
  68. */
  69. private function createController(string $base_name): void {
  70. if (self::isRegistered($base_name)) {
  71. self::loadController($base_name);
  72. $controller_name = 'FreshExtension_' . $base_name . '_Controller';
  73. } else {
  74. $controller_name = 'FreshRSS_' . $base_name . '_Controller';
  75. }
  76. if (!class_exists($controller_name)) {
  77. throw new Minz_ControllerNotExistException(
  78. Minz_Exception::ERROR
  79. );
  80. }
  81. $controller = new $controller_name();
  82. if (!($controller instanceof Minz_ActionController)) {
  83. throw new Minz_ControllerNotActionControllerException(
  84. $controller_name,
  85. Minz_Exception::ERROR
  86. );
  87. }
  88. $this->controller = $controller;
  89. }
  90. /**
  91. * Launch the action on the dispatcher’s controller
  92. * @param string $action_name the name of the action
  93. * @throws Minz_ActionException if the action cannot be executed on the controller
  94. */
  95. private function launchAction(string $action_name): void {
  96. $call = [$this->controller, $action_name];
  97. if (!is_callable($call)) {
  98. throw new Minz_ActionException(
  99. get_class($this->controller),
  100. $action_name,
  101. Minz_Exception::ERROR
  102. );
  103. }
  104. call_user_func($call);
  105. }
  106. /**
  107. * Register a controller file.
  108. *
  109. * @param string $base_name the base name of the controller (i.e. ./?c=<base_name>)
  110. * @param string $base_path the base path where we should look into to find info.
  111. */
  112. public static function registerController(string $base_name, string $base_path): void {
  113. if (!self::isRegistered($base_name)) {
  114. self::$registrations[$base_name] = $base_path;
  115. }
  116. }
  117. /**
  118. * Return if a controller is registered.
  119. *
  120. * @param string $base_name the base name of the controller.
  121. * @return bool true if the controller has been registered, false else.
  122. */
  123. public static function isRegistered(string $base_name): bool {
  124. return isset(self::$registrations[$base_name]);
  125. }
  126. /**
  127. * Load a controller file (include).
  128. *
  129. * @param string $base_name the base name of the controller.
  130. */
  131. private static function loadController(string $base_name): void {
  132. $base_path = self::$registrations[$base_name];
  133. $controller_filename = $base_path . '/Controllers/' . $base_name . 'Controller.php';
  134. include_once $controller_filename;
  135. }
  136. }