diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index d4d07411f70e7..c3f62a9267f35 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add `UploadedFile::getClientOriginalPath()` + * Add `QueryParameterRequestMatcher` 7.0 --- diff --git a/src/Symfony/Component/HttpFoundation/RequestMatcher/QueryParameterRequestMatcher.php b/src/Symfony/Component/HttpFoundation/RequestMatcher/QueryParameterRequestMatcher.php new file mode 100644 index 0000000000000..86161e7c031dc --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/RequestMatcher/QueryParameterRequestMatcher.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\RequestMatcher; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestMatcherInterface; + +/** + * Checks the presence of HTTP query parameters of a Request. + * + * @author Alexandre Daubois + */ +class QueryParameterRequestMatcher implements RequestMatcherInterface +{ + /** + * @var string[] + */ + private array $parameters; + + /** + * @param string[]|string $parameters A parameter or a list of parameters + * Strings can contain a comma-delimited list of query parameters + */ + public function __construct(array|string $parameters) + { + $this->parameters = array_reduce(array_map(strtolower(...), (array) $parameters), static fn (array $parameters, string $parameter) => array_merge($parameters, preg_split('/\s*,\s*/', $parameter)), []); + } + + public function matches(Request $request): bool + { + if (!$this->parameters) { + return true; + } + + return 0 === \count(array_diff_assoc($this->parameters, $request->query->keys())); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestMatcher/QueryParameterRequestMatcherTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcher/QueryParameterRequestMatcherTest.php new file mode 100644 index 0000000000000..202ca649ab05f --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcher/QueryParameterRequestMatcherTest.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\RequestMatcher; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestMatcher\QueryParameterRequestMatcher; + +class QueryParameterRequestMatcherTest extends TestCase +{ + /** + * @dataProvider getDataForArray + */ + public function testArray(string $uri, bool $matches) + { + $matcher = new QueryParameterRequestMatcher(['foo', 'bar']); + $request = Request::create($uri); + $this->assertSame($matches, $matcher->matches($request)); + } + + /** + * @dataProvider getDataForArray + */ + public function testCommaSeparatedString(string $uri, bool $matches) + { + $matcher = new QueryParameterRequestMatcher('foo, bar'); + $request = Request::create($uri); + $this->assertSame($matches, $matcher->matches($request)); + } + + /** + * @dataProvider getDataForSingleString + */ + public function testSingleString(string $uri, bool $matches) + { + $matcher = new QueryParameterRequestMatcher('foo'); + $request = Request::create($uri); + $this->assertSame($matches, $matcher->matches($request)); + } + + public static function getDataForArray(): \Generator + { + yield ['https://example.com?foo=&bar=', true]; + yield ['https://example.com?foo=foo1&bar=bar1', true]; + yield ['https://example.com?foo=foo1&bar=bar1&baz=baz1', true]; + yield ['https://example.com?foo=', false]; + yield ['https://example.com', false]; + } + + public static function getDataForSingleString(): \Generator + { + yield ['https://example.com?foo=&bar=', true]; + yield ['https://example.com?foo=foo1', true]; + yield ['https://example.com?foo=', true]; + yield ['https://example.com?bar=bar1&baz=baz1', false]; + yield ['https://example.com', false]; + } +}