66
77use InvalidArgumentException ;
88use RuntimeException ;
9- use Yiisoft \Middleware \ Dispatcher \ MiddlewareDispatcher ;
9+ use Yiisoft \Router \ Internal \ MiddlewareFilter ;
1010
1111use function in_array ;
1212
@@ -15,12 +15,13 @@ final class Group
1515 /**
1616 * @var Group[]|Route[]
1717 */
18- private array $ items = [];
18+ private array $ routes = [];
1919
2020 /**
2121 * @var array[]|callable[]|string[]
22+ * @psalm-var list<array|callable|string>
2223 */
23- private array $ middlewareDefinitions = [];
24+ private array $ middlewares = [];
2425
2526 /**
2627 * @var string[]
@@ -29,62 +30,46 @@ final class Group
2930 private ?string $ namePrefix = null ;
3031 private bool $ routesAdded = false ;
3132 private bool $ middlewareAdded = false ;
32- private array $ disabledMiddlewareDefinitions = [];
33+ private array $ disabledMiddlewares = [];
34+
35+ /**
36+ * @psalm-var list<array|callable|string>|null
37+ */
38+ private ?array $ enabledMiddlewaresCache = null ;
3339
3440 /**
3541 * @var array|callable|string|null Middleware definition for CORS requests.
3642 */
3743 private $ corsMiddleware = null ;
3844
39- private function __construct (private ?string $ prefix = null , private ?MiddlewareDispatcher $ dispatcher = null )
40- {
45+ private function __construct (
46+ private ?string $ prefix = null
47+ ) {
4148 }
4249
4350 /**
4451 * Create a new group instance.
4552 *
4653 * @param string|null $prefix URL prefix to prepend to all routes of the group.
47- * @param MiddlewareDispatcher|null $dispatcher Middleware dispatcher to use for the group.
4854 */
49- public static function create (
50- ?string $ prefix = null ,
51- MiddlewareDispatcher $ dispatcher = null
52- ): self {
53- return new self ($ prefix , $ dispatcher );
55+ public static function create (?string $ prefix = null ): self
56+ {
57+ return new self ($ prefix );
5458 }
5559
5660 public function routes (self |Route ...$ routes ): self
5761 {
5862 if ($ this ->middlewareAdded ) {
5963 throw new RuntimeException ('routes() can not be used after prependMiddleware(). ' );
6064 }
61- $ new = clone $ this ;
62- foreach ($ routes as $ route ) {
63- if ($ new ->dispatcher !== null && !$ route ->getData ('hasDispatcher ' )) {
64- $ route = $ route ->withDispatcher ($ new ->dispatcher );
65- }
66- $ new ->items [] = $ route ;
67- }
6865
66+ $ new = clone $ this ;
67+ $ new ->routes = $ routes ;
6968 $ new ->routesAdded = true ;
7069
7170 return $ new ;
7271 }
7372
74- public function withDispatcher (MiddlewareDispatcher $ dispatcher ): self
75- {
76- $ group = clone $ this ;
77- $ group ->dispatcher = $ dispatcher ;
78- foreach ($ group ->items as $ index => $ item ) {
79- if (!$ item ->getData ('hasDispatcher ' )) {
80- $ item = $ item ->withDispatcher ($ dispatcher );
81- $ group ->items [$ index ] = $ item ;
82- }
83- }
84-
85- return $ group ;
86- }
87-
8873 /**
8974 * Adds a middleware definition that handles CORS requests.
9075 * If set, routes for {@see Method::OPTIONS} request will be added automatically.
@@ -103,31 +88,38 @@ public function withCors(array|callable|string|null $middlewareDefinition): self
10388 * Appends a handler middleware definition that should be invoked for a matched route.
10489 * First added handler will be executed first.
10590 */
106- public function middleware (array |callable |string ...$ middlewareDefinition ): self
91+ public function middleware (array |callable |string ...$ definition ): self
10792 {
10893 if ($ this ->routesAdded ) {
10994 throw new RuntimeException ('middleware() can not be used after routes(). ' );
11095 }
96+
11197 $ new = clone $ this ;
11298 array_push (
113- $ new ->middlewareDefinitions ,
114- ...array_values ($ middlewareDefinition )
99+ $ new ->middlewares ,
100+ ...array_values ($ definition )
115101 );
102+
103+ $ new ->enabledMiddlewaresCache = null ;
104+
116105 return $ new ;
117106 }
118107
119108 /**
120109 * Prepends a handler middleware definition that should be invoked for a matched route.
121110 * First added handler will be executed last.
122111 */
123- public function prependMiddleware (array |callable |string ...$ middlewareDefinition ): self
112+ public function prependMiddleware (array |callable |string ...$ definition ): self
124113 {
125114 $ new = clone $ this ;
126115 array_unshift (
127- $ new ->middlewareDefinitions ,
128- ...array_values ($ middlewareDefinition )
116+ $ new ->middlewares ,
117+ ...array_values ($ definition )
129118 );
119+
130120 $ new ->middlewareAdded = true ;
121+ $ new ->enabledMiddlewaresCache = null ;
122+
131123 return $ new ;
132124 }
133125
@@ -163,13 +155,16 @@ public function hosts(string ...$hosts): self
163155 * It is useful to avoid invoking one of the parent group middleware for
164156 * a certain route.
165157 */
166- public function disableMiddleware (mixed ...$ middlewareDefinition ): self
158+ public function disableMiddleware (mixed ...$ definition ): self
167159 {
168160 $ new = clone $ this ;
169161 array_push (
170- $ new ->disabledMiddlewareDefinitions ,
171- ...array_values ($ middlewareDefinition ),
162+ $ new ->disabledMiddlewares ,
163+ ...array_values ($ definition ),
172164 );
165+
166+ $ new ->enabledMiddlewaresCache = null ;
167+
173168 return $ new ;
174169 }
175170
@@ -180,10 +175,10 @@ public function disableMiddleware(mixed ...$middlewareDefinition): self
180175 *
181176 * @psalm-return (
182177 * T is ('prefix'|'namePrefix'|'host') ? string|null :
183- * (T is 'items ' ? Group[]|Route[] :
178+ * (T is 'routes ' ? Group[]|Route[] :
184179 * (T is 'hosts' ? array<array-key, string> :
185- * (T is ('hasCorsMiddleware'|'hasDispatcher' ) ? bool :
186- * (T is 'middlewareDefinitions ' ? list<array|callable|string> :
180+ * (T is ('hasCorsMiddleware') ? bool :
181+ * (T is 'enabledMiddlewares ' ? list<array|callable|string> :
187182 * (T is 'corsMiddleware' ? array|callable|string|null : mixed)
188183 * )
189184 * )
@@ -199,23 +194,25 @@ public function getData(string $key): mixed
199194 'host ' => $ this ->hosts [0 ] ?? null ,
200195 'hosts ' => $ this ->hosts ,
201196 'corsMiddleware ' => $ this ->corsMiddleware ,
202- 'items ' => $ this ->items ,
197+ 'routes ' => $ this ->routes ,
203198 'hasCorsMiddleware ' => $ this ->corsMiddleware !== null ,
204- 'hasDispatcher ' => $ this ->dispatcher !== null ,
205- 'middlewareDefinitions ' => $ this ->getMiddlewareDefinitions (),
199+ 'enabledMiddlewares ' => $ this ->getEnabledMiddlewares (),
206200 default => throw new InvalidArgumentException ('Unknown data key: ' . $ key ),
207201 };
208202 }
209203
210- private function getMiddlewareDefinitions (): array
204+ /**
205+ * @return array[]|callable[]|string[]
206+ * @psalm-return list<array|callable|string>
207+ */
208+ private function getEnabledMiddlewares (): array
211209 {
212- /** @var mixed $definition */
213- foreach ($ this ->middlewareDefinitions as $ index => $ definition ) {
214- if (in_array ($ definition , $ this ->disabledMiddlewareDefinitions , true )) {
215- unset($ this ->middlewareDefinitions [$ index ]);
216- }
210+ if ($ this ->enabledMiddlewaresCache !== null ) {
211+ return $ this ->enabledMiddlewaresCache ;
217212 }
218213
219- return array_values ($ this ->middlewareDefinitions );
214+ $ this ->enabledMiddlewaresCache = MiddlewareFilter::filter ($ this ->middlewares , $ this ->disabledMiddlewares );
215+
216+ return $ this ->enabledMiddlewaresCache ;
220217 }
221218}
0 commit comments