MiddlewareQueue.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.3.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Http;
  16. use Cake\Core\App;
  17. use Countable;
  18. use LogicException;
  19. use RuntimeException;
  20. /**
  21. * Provides methods for creating and manipulating a "queue" of middleware callables.
  22. * This queue is used to process a request and response via \Cake\Http\Runner.
  23. */
  24. class MiddlewareQueue implements Countable
  25. {
  26. /**
  27. * The queue of middlewares.
  28. *
  29. * @var array
  30. */
  31. protected $queue = [];
  32. /**
  33. * The queue of middleware callables.
  34. *
  35. * @var callable[]
  36. */
  37. protected $callables = [];
  38. /**
  39. * Get the middleware at the provided index.
  40. *
  41. * @param int $index The index to fetch.
  42. * @return callable|null Either the callable middleware or null
  43. * if the index is undefined.
  44. */
  45. public function get($index)
  46. {
  47. if (isset($this->callables[$index])) {
  48. return $this->callables[$index];
  49. }
  50. return $this->resolve($index);
  51. }
  52. /**
  53. * Resolve middleware name to callable.
  54. *
  55. * @param int $index The index to fetch.
  56. * @return callable|null Either the callable middleware or null
  57. * if the index is undefined.
  58. */
  59. protected function resolve($index)
  60. {
  61. if (!isset($this->queue[$index])) {
  62. return null;
  63. }
  64. if (is_string($this->queue[$index])) {
  65. $class = $this->queue[$index];
  66. $className = App::className($class, 'Middleware', 'Middleware');
  67. if (!$className || !class_exists($className)) {
  68. throw new RuntimeException(sprintf(
  69. 'Middleware "%s" was not found.',
  70. $class
  71. ));
  72. }
  73. $callable = new $className;
  74. } else {
  75. $callable = $this->queue[$index];
  76. }
  77. return $this->callables[$index] = $callable;
  78. }
  79. /**
  80. * Append a middleware callable to the end of the queue.
  81. *
  82. * @param callable|string|array $middleware The middleware(s) to append.
  83. * @return $this
  84. */
  85. public function add($middleware)
  86. {
  87. if (is_array($middleware)) {
  88. $this->queue = array_merge($this->queue, $middleware);
  89. return $this;
  90. }
  91. $this->queue[] = $middleware;
  92. return $this;
  93. }
  94. /**
  95. * Alias for MiddlewareQueue::add().
  96. *
  97. * @param callable|string|array $middleware The middleware(s) to append.
  98. * @return $this
  99. * @see MiddlewareQueue::add()
  100. */
  101. public function push($middleware)
  102. {
  103. return $this->add($middleware);
  104. }
  105. /**
  106. * Prepend a middleware to the start of the queue.
  107. *
  108. * @param callable|string|array $middleware The middleware(s) to prepend.
  109. * @return $this
  110. */
  111. public function prepend($middleware)
  112. {
  113. if (is_array($middleware)) {
  114. $this->queue = array_merge($middleware, $this->queue);
  115. return $this;
  116. }
  117. array_unshift($this->queue, $middleware);
  118. return $this;
  119. }
  120. /**
  121. * Insert a middleware callable at a specific index.
  122. *
  123. * If the index already exists, the new callable will be inserted,
  124. * and the existing element will be shifted one index greater.
  125. *
  126. * @param int $index The index to insert at.
  127. * @param callable|string $middleware The middleware to insert.
  128. * @return $this
  129. */
  130. public function insertAt($index, $middleware)
  131. {
  132. array_splice($this->queue, $index, 0, [$middleware]);
  133. return $this;
  134. }
  135. /**
  136. * Insert a middleware object before the first matching class.
  137. *
  138. * Finds the index of the first middleware that matches the provided class,
  139. * and inserts the supplied callable before it.
  140. *
  141. * @param string $class The classname to insert the middleware before.
  142. * @param callable|string $middleware The middleware to insert.
  143. * @return $this
  144. * @throws \LogicException If middleware to insert before is not found.
  145. */
  146. public function insertBefore($class, $middleware)
  147. {
  148. $found = false;
  149. $i = null;
  150. foreach ($this->queue as $i => $object) {
  151. if ((is_string($object) && $object === $class)
  152. || is_a($object, $class)
  153. ) {
  154. $found = true;
  155. break;
  156. }
  157. }
  158. if ($found) {
  159. return $this->insertAt($i, $middleware);
  160. }
  161. throw new LogicException(sprintf("No middleware matching '%s' could be found.", $class));
  162. }
  163. /**
  164. * Insert a middleware object after the first matching class.
  165. *
  166. * Finds the index of the first middleware that matches the provided class,
  167. * and inserts the supplied callable after it. If the class is not found,
  168. * this method will behave like add().
  169. *
  170. * @param string $class The classname to insert the middleware before.
  171. * @param callable|string $middleware The middleware to insert.
  172. * @return $this
  173. */
  174. public function insertAfter($class, $middleware)
  175. {
  176. $found = false;
  177. $i = null;
  178. foreach ($this->queue as $i => $object) {
  179. if ((is_string($object) && $object === $class)
  180. || is_a($object, $class)
  181. ) {
  182. $found = true;
  183. break;
  184. }
  185. }
  186. if ($found) {
  187. return $this->insertAt($i + 1, $middleware);
  188. }
  189. return $this->add($middleware);
  190. }
  191. /**
  192. * Get the number of connected middleware layers.
  193. *
  194. * Implement the Countable interface.
  195. *
  196. * @return int
  197. */
  198. public function count()
  199. {
  200. return count($this->queue);
  201. }
  202. }