Dispatcher.php 4.2 KB

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