1111
1212namespace Symfony \Component \HttpFoundation ;
1313
14+ use Symfony \Component \HttpFoundation \RequestMatcher \AttributesRequestMatcher ;
15+ use Symfony \Component \HttpFoundation \RequestMatcher \HostRequestMatcher ;
16+ use Symfony \Component \HttpFoundation \RequestMatcher \IpsRequestMatcher ;
17+ use Symfony \Component \HttpFoundation \RequestMatcher \MethodRequestMatcher ;
18+ use Symfony \Component \HttpFoundation \RequestMatcher \PathRequestMatcher ;
19+ use Symfony \Component \HttpFoundation \RequestMatcher \PortRequestMatcher ;
20+ use Symfony \Component \HttpFoundation \RequestMatcher \SchemeRequestMatcher ;
21+
1422/**
1523 * RequestMatcher compares a pre-defined set of checks against a Request instance.
1624 *
1725 * @author Fabien Potencier <fabien@symfony.com>
1826 */
1927class RequestMatcher implements RequestMatcherInterface
2028{
21- private ?string $ path = null ;
22- private ?string $ host = null ;
23- private ?int $ port = null ;
24-
2529 /**
26- * @var string []
30+ * @var RequestMatcherInterface []
2731 */
28- private array $ methods = [];
29-
30- /**
31- * @var string[]
32- */
33- private array $ ips = [];
34-
35- /**
36- * @var string[]
37- */
38- private array $ attributes = [];
39-
40- /**
41- * @var string[]
42- */
43- private array $ schemes = [];
32+ private array $ matchers = [];
4433
4534 /**
4635 * @param string|string[]|null $methods
@@ -61,22 +50,49 @@ public function __construct(string $path = null, string $host = null, string|arr
6150 }
6251 }
6352
53+ /**
54+ * @return $this
55+ */
56+ public function add (RequestMatcherInterface $ matcher ): static
57+ {
58+ $ this ->matchers [$ matcher ::class] = $ matcher ;
59+
60+ return $ this ;
61+ }
62+
63+ public function remove (string $ class )
64+ {
65+ unset($ this ->matchers [$ class ]);
66+ }
67+
6468 /**
6569 * Adds a check for the HTTP scheme.
6670 *
6771 * @param string|string[]|null $scheme An HTTP scheme or an array of HTTP schemes
6872 */
6973 public function matchScheme (string |array |null $ scheme )
7074 {
71- $ this ->schemes = null !== $ scheme ? array_map ('strtolower ' , (array ) $ scheme ) : [];
75+ if (null === $ scheme || !count ($ scheme )) {
76+ $ this ->remove (SchemeRequestMatcher::class);
77+
78+ return ;
79+ }
80+
81+ $ this ->add (new SchemeRequestMatcher ($ scheme ));
7282 }
7383
7484 /**
7585 * Adds a check for the URL host name.
7686 */
7787 public function matchHost (?string $ regexp )
7888 {
79- $ this ->host = $ regexp ;
89+ if (null === $ regexp ) {
90+ $ this ->remove (HostRequestMatcher::class);
91+
92+ return ;
93+ }
94+
95+ $ this ->add (new HostRequestMatcher ($ regexp ));
8096 }
8197
8298 /**
@@ -86,15 +102,27 @@ public function matchHost(?string $regexp)
86102 */
87103 public function matchPort (?int $ port )
88104 {
89- $ this ->port = $ port ;
105+ if (null === $ port ) {
106+ $ this ->remove (PortRequestMatcher::class);
107+
108+ return ;
109+ }
110+
111+ $ this ->add (new PortRequestMatcher ($ port ));
90112 }
91113
92114 /**
93115 * Adds a check for the URL path info.
94116 */
95117 public function matchPath (?string $ regexp )
96118 {
97- $ this ->path = $ regexp ;
119+ if (null === $ regexp ) {
120+ $ this ->remove (PathRequestMatcher::class);
121+
122+ return ;
123+ }
124+
125+ $ this ->add (new PathRequestMatcher ($ regexp ));
98126 }
99127
100128 /**
@@ -114,69 +142,47 @@ public function matchIp(string $ip)
114142 */
115143 public function matchIps (string |array |null $ ips )
116144 {
117- $ ips = null !== $ ips ? (array ) $ ips : [];
145+ if (null === $ ips || !count ($ ips )) {
146+ $ this ->remove (IpsRequestMatcher::class);
118147
119- $ this ->ips = array_reduce ($ ips , static function (array $ ips , string $ ip ) {
120- return array_merge ($ ips , preg_split ('/\s*,\s*/ ' , $ ip ));
121- }, []);
148+ return ;
149+ }
150+
151+ $ this ->add (new IpsRequestMatcher ($ ips ));
122152 }
123153
124154 /**
125155 * Adds a check for the HTTP method.
126156 *
127- * @param string|string[]|null $method An HTTP method or an array of HTTP methods
157+ * @param string|string[]|null $method
128158 */
129159 public function matchMethod (string |array |null $ method )
130160 {
131- $ this ->methods = null !== $ method ? array_map ('strtoupper ' , (array ) $ method ) : [];
161+ if (null === $ method || !count ($ method )) {
162+ $ this ->remove (MethodRequestMatcher::class);
163+
164+ return ;
165+ }
166+
167+ $ this ->add (new MethodRequestMatcher ($ method ));
132168 }
133169
134170 /**
135171 * Adds a check for request attribute.
136172 */
137173 public function matchAttribute (string $ key , string $ regexp )
138174 {
139- $ this ->attributes [ $ key ] = $ regexp ;
175+ ( $ this ->matchers [AttributesRequestMatcher::class] ??= new AttributesRequestMatcher ([]))-> addAttributeCheck ( $ key , $ regexp) ;
140176 }
141177
142178 public function matches (Request $ request ): bool
143179 {
144- if ($ this ->schemes && !\in_array ($ request ->getScheme (), $ this ->schemes , true )) {
145- return false ;
146- }
147-
148- if ($ this ->methods && !\in_array ($ request ->getMethod (), $ this ->methods , true )) {
149- return false ;
150- }
151-
152- foreach ($ this ->attributes as $ key => $ pattern ) {
153- $ requestAttribute = $ request ->attributes ->get ($ key );
154- if (!\is_string ($ requestAttribute )) {
155- return false ;
156- }
157- if (!preg_match ('{ ' .$ pattern .'} ' , $ requestAttribute )) {
180+ foreach ($ this ->matchers as $ matcher ) {
181+ if (!$ matcher ->matches ($ request )) {
158182 return false ;
159183 }
160184 }
161185
162- if (null !== $ this ->path && !preg_match ('{ ' .$ this ->path .'} ' , rawurldecode ($ request ->getPathInfo ()))) {
163- return false ;
164- }
165-
166- if (null !== $ this ->host && !preg_match ('{ ' .$ this ->host .'}i ' , $ request ->getHost ())) {
167- return false ;
168- }
169-
170- if (null !== $ this ->port && 0 < $ this ->port && $ request ->getPort () !== $ this ->port ) {
171- return false ;
172- }
173-
174- if (IpUtils::checkIp ($ request ->getClientIp () ?? '' , $ this ->ips )) {
175- return true ;
176- }
177-
178- // Note to future implementors: add additional checks above the
179- // foreach above or else your check might not be run!
180- return 0 === \count ($ this ->ips );
186+ return true ;
181187 }
182188}
0 commit comments