MiddlewareDispatcher.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  6. * SPDX-License-Identifier: AGPL-3.0-only
  7. */
  8. namespace OC\AppFramework\Middleware;
  9. use OCP\AppFramework\Controller;
  10. use OCP\AppFramework\Http\Response;
  11. use OCP\AppFramework\Middleware;
  12. /**
  13. * This class is used to store and run all the middleware in correct order
  14. */
  15. class MiddlewareDispatcher {
  16. /**
  17. * @var Middleware[] array containing all the middlewares
  18. */
  19. private array $middlewares;
  20. /**
  21. * @var int counter which tells us what middleware was executed once an
  22. * exception occurs
  23. */
  24. private int $middlewareCounter;
  25. /**
  26. * Constructor
  27. */
  28. public function __construct() {
  29. $this->middlewares = [];
  30. $this->middlewareCounter = 0;
  31. }
  32. /**
  33. * Adds a new middleware
  34. * @param Middleware $middleWare the middleware which will be added
  35. */
  36. public function registerMiddleware(Middleware $middleWare): void {
  37. $this->middlewares[] = $middleWare;
  38. }
  39. /**
  40. * returns an array with all middleware elements
  41. * @return Middleware[] the middlewares
  42. */
  43. public function getMiddlewares(): array {
  44. return $this->middlewares;
  45. }
  46. /**
  47. * This is being run in normal order before the controller is being
  48. * called which allows several modifications and checks
  49. *
  50. * @param Controller $controller the controller that is being called
  51. * @param string $methodName the name of the method that will be called on
  52. * the controller
  53. */
  54. public function beforeController(Controller $controller, string $methodName): void {
  55. // we need to count so that we know which middlewares we have to ask in
  56. // case there is an exception
  57. $middlewareCount = \count($this->middlewares);
  58. for ($i = 0; $i < $middlewareCount; $i++) {
  59. $this->middlewareCounter++;
  60. $middleware = $this->middlewares[$i];
  61. $middleware->beforeController($controller, $methodName);
  62. }
  63. }
  64. /**
  65. * This is being run when either the beforeController method or the
  66. * controller method itself is throwing an exception. The middleware is asked
  67. * in reverse order to handle the exception and to return a response.
  68. * If the response is null, it is assumed that the exception could not be
  69. * handled and the error will be thrown again
  70. *
  71. * @param Controller $controller the controller that is being called
  72. * @param string $methodName the name of the method that will be called on
  73. * the controller
  74. * @param \Exception $exception the thrown exception
  75. * @return Response a Response object if the middleware can handle the
  76. * exception
  77. * @throws \Exception the passed in exception if it can't handle it
  78. */
  79. public function afterException(Controller $controller, string $methodName, \Exception $exception): Response {
  80. for ($i = $this->middlewareCounter - 1; $i >= 0; $i--) {
  81. $middleware = $this->middlewares[$i];
  82. try {
  83. return $middleware->afterException($controller, $methodName, $exception);
  84. } catch (\Exception $exception) {
  85. continue;
  86. }
  87. }
  88. throw $exception;
  89. }
  90. /**
  91. * This is being run after a successful controllermethod call and allows
  92. * the manipulation of a Response object. The middleware is run in reverse order
  93. *
  94. * @param Controller $controller the controller that is being called
  95. * @param string $methodName the name of the method that will be called on
  96. * the controller
  97. * @param Response $response the generated response from the controller
  98. * @return Response a Response object
  99. */
  100. public function afterController(Controller $controller, string $methodName, Response $response): Response {
  101. for ($i = \count($this->middlewares) - 1; $i >= 0; $i--) {
  102. $middleware = $this->middlewares[$i];
  103. $response = $middleware->afterController($controller, $methodName, $response);
  104. }
  105. return $response;
  106. }
  107. /**
  108. * This is being run after the response object has been rendered and
  109. * allows the manipulation of the output. The middleware is run in reverse order
  110. *
  111. * @param Controller $controller the controller that is being called
  112. * @param string $methodName the name of the method that will be called on
  113. * the controller
  114. * @param string $output the generated output from a response
  115. * @return string the output that should be printed
  116. */
  117. public function beforeOutput(Controller $controller, string $methodName, string $output): string {
  118. for ($i = \count($this->middlewares) - 1; $i >= 0; $i--) {
  119. $middleware = $this->middlewares[$i];
  120. $output = $middleware->beforeOutput($controller, $methodName, $output);
  121. }
  122. return $output;
  123. }
  124. }