Skip to content

Commit 019f84d

Browse files
refactor: validate that variadic functions have only the expected count of arguments (#274)
1 parent 877d929 commit 019f84d

File tree

18 files changed

+226
-3
lines changed

18 files changed

+226
-3
lines changed

src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/BaseVariadicFunction.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public function feedParserWithNodes(Parser $parser): void
3838
}
3939
$aheadType = $lexer->lookahead->type;
4040
}
41+
42+
$this->validateArguments($this->nodes);
4143
}
4244

4345
public function getSql(SqlWalker $sqlWalker): string
@@ -49,4 +51,11 @@ public function getSql(SqlWalker $sqlWalker): string
4951

5052
return \sprintf($this->functionPrototype, \implode(', ', $dispatched));
5153
}
54+
55+
/**
56+
* Validates the arguments passed to the function.
57+
*
58+
* @param mixed[] $arguments The array of arguments to validate
59+
*/
60+
abstract protected function validateArguments(array $arguments): void;
5261
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception;
6+
7+
class InvalidArgumentForVariadicFunctionException extends \InvalidArgumentException
8+
{
9+
public static function exactCount(string $functionName, int $expected): self
10+
{
11+
return new self(\sprintf(
12+
'%s() requires exactly %d argument%s',
13+
$functionName,
14+
$expected,
15+
$expected === 1 ? '' : 's'
16+
));
17+
}
18+
19+
public static function atLeast(string $functionName, int $min): self
20+
{
21+
return new self(\sprintf(
22+
'%s() requires at least %d argument%s',
23+
$functionName,
24+
$min,
25+
$min === 1 ? '' : 's'
26+
));
27+
}
28+
29+
public static function between(string $functionName, int $min, int $max): self
30+
{
31+
return new self(\sprintf(
32+
'%s() requires between %d and %d arguments',
33+
$functionName,
34+
$min,
35+
$max
36+
));
37+
}
38+
39+
public static function evenNumber(string $functionName): self
40+
{
41+
return new self(\sprintf(
42+
'%s() requires an even number of arguments',
43+
$functionName
44+
));
45+
}
46+
}

src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Greatest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
66

7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
8+
79
/**
810
* Implementation of PostgreSQL GREATEST().
911
*
@@ -18,4 +20,12 @@ protected function customizeFunction(): void
1820
{
1921
$this->setFunctionPrototype('greatest(%s)');
2022
}
23+
24+
protected function validateArguments(array $arguments): void
25+
{
26+
$argumentCount = \count($arguments);
27+
if ($argumentCount < 2) {
28+
throw InvalidArgumentForVariadicFunctionException::atLeast('greatest', 2);
29+
}
30+
}
2131
}

src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonBuildObject.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,28 @@
44

55
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
66

7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
8+
79
/**
810
* Implementation of PostgreSQL JSON_BUILD_OBJECT().
911
*
1012
* @see https://www.postgresql.org/docs/17/functions-json.html
11-
* @since 2.9.0
13+
* @since 2.9
14+
*
15+
* @author Martin Georgiev <martin.georgiev@gmail.com>
1216
*/
1317
class JsonBuildObject extends BaseVariadicFunction
1418
{
1519
protected function customizeFunction(): void
1620
{
1721
$this->setFunctionPrototype('json_build_object(%s)');
1822
}
23+
24+
protected function validateArguments(array $arguments): void
25+
{
26+
$argumentCount = \count($arguments);
27+
if ($argumentCount === 0 || $argumentCount % 2 !== 0) {
28+
throw InvalidArgumentForVariadicFunctionException::evenNumber('json_build_object');
29+
}
30+
}
1931
}

src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbBuildObject.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,28 @@
44

55
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
66

7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
8+
79
/**
810
* Implementation of PostgreSQL JSONB_BUILD_OBJECT().
911
*
1012
* @see https://www.postgresql.org/docs/17/functions-json.html
11-
* @since 2.9.0
13+
* @since 2.9
14+
*
15+
* @author Martin Georgiev <martin.georgiev@gmail.com>
1216
*/
1317
class JsonbBuildObject extends BaseVariadicFunction
1418
{
1519
protected function customizeFunction(): void
1620
{
1721
$this->setFunctionPrototype('jsonb_build_object(%s)');
1822
}
23+
24+
protected function validateArguments(array $arguments): void
25+
{
26+
$argumentCount = \count($arguments);
27+
if ($argumentCount === 0 || $argumentCount % 2 !== 0) {
28+
throw InvalidArgumentForVariadicFunctionException::evenNumber('jsonb_build_object');
29+
}
30+
}
1931
}

src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Least.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
66

7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
8+
79
/**
810
* Implementation of PostgreSQL LEAST().
911
*
@@ -18,4 +20,12 @@ protected function customizeFunction(): void
1820
{
1921
$this->setFunctionPrototype('least(%s)');
2022
}
23+
24+
protected function validateArguments(array $arguments): void
25+
{
26+
$argumentCount = \count($arguments);
27+
if ($argumentCount < 2) {
28+
throw InvalidArgumentForVariadicFunctionException::atLeast('least', 2);
29+
}
30+
}
2131
}

src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Row.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
66

7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
8+
79
/**
810
* Implementation of PostgreSQL Row Constructor expression.
911
*
@@ -17,4 +19,12 @@ protected function customizeFunction(): void
1719
{
1820
$this->setFunctionPrototype('ROW(%s)');
1921
}
22+
23+
protected function validateArguments(array $arguments): void
24+
{
25+
$argumentCount = \count($arguments);
26+
if ($argumentCount === 0) {
27+
throw InvalidArgumentForVariadicFunctionException::atLeast('ROW', 1);
28+
}
29+
}
2030
}

src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTsquery.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
66

7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
8+
79
/**
810
* Implementation of PostgreSQL TO_TSQUERY().
911
*
@@ -18,4 +20,12 @@ protected function customizeFunction(): void
1820
{
1921
$this->setFunctionPrototype('to_tsquery(%s)');
2022
}
23+
24+
protected function validateArguments(array $arguments): void
25+
{
26+
$argumentCount = \count($arguments);
27+
if ($argumentCount < 1 || $argumentCount > 2) {
28+
throw InvalidArgumentForVariadicFunctionException::between('to_tsquery', 1, 2);
29+
}
30+
}
2131
}

src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToTsvector.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
66

7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
8+
79
/**
810
* Implementation of PostgreSQL TO_TSVECTOR().
911
*
@@ -20,4 +22,12 @@ protected function customizeFunction(): void
2022
{
2123
$this->setFunctionPrototype('to_tsvector(%s)');
2224
}
25+
26+
protected function validateArguments(array $arguments): void
27+
{
28+
$argumentCount = \count($arguments);
29+
if ($argumentCount < 1 || $argumentCount > 2) {
30+
throw InvalidArgumentForVariadicFunctionException::between('to_tsvector', 1, 2);
31+
}
32+
}
2333
}

src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Unaccent.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
66

7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
8+
79
/**
810
* Implementation of PostgreSQL UNACCENT.
911
*
@@ -19,4 +21,12 @@ protected function customizeFunction(): void
1921
{
2022
$this->setFunctionPrototype('unaccent(%s)');
2123
}
24+
25+
protected function validateArguments(array $arguments): void
26+
{
27+
$argumentCount = \count($arguments);
28+
if ($argumentCount < 1 || $argumentCount > 2) {
29+
throw InvalidArgumentForVariadicFunctionException::between('unaccent', 1, 2);
30+
}
31+
}
2232
}

0 commit comments

Comments
 (0)