From 8144aaf3ec1a3dd3fb483869d53ccea17437e313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 7 Jan 2025 16:55:27 +0100 Subject: [PATCH 1/2] PHPLIB-1587 Validate hint option using is_document --- src/Exception/InvalidArgumentException.php | 11 +++++++++++ src/Operation/Aggregate.php | 5 ++--- src/Operation/Count.php | 4 ++-- src/Operation/Delete.php | 6 ++---- src/Operation/Distinct.php | 2 +- src/Operation/Find.php | 4 ++-- src/Operation/FindAndModify.php | 4 ++-- src/Operation/Update.php | 5 ++--- tests/TestCase.php | 2 +- 9 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php index 115f6a5c7..964b259c1 100644 --- a/src/Exception/InvalidArgumentException.php +++ b/src/Exception/InvalidArgumentException.php @@ -34,6 +34,17 @@ public static function cannotCombineCodecAndTypeMap(): self return new self('Cannot provide both "codec" and "typeMap" options'); } + /** + * Thrown when an argument or option is expected to be a string or a document. + * + * @param string $name Name of the argument or option + * @param mixed $value Actual value (used to derive the type) + */ + public static function expectedDocumentOrStringType(string $name, mixed $value): self + { + return new self(sprintf('Expected %s to have type "string" or "document" (array or object) but found "%s"', $name, get_debug_type($value))); + } + /** * Thrown when an argument or option is expected to be a document. * diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 3543fc73c..7c968a250 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -37,7 +37,6 @@ use function is_array; use function is_bool; use function is_integer; -use function is_object; use function is_string; use function MongoDB\is_document; use function MongoDB\is_last_pipeline_operator_write; @@ -150,8 +149,8 @@ public function __construct(private string $databaseName, private ?string $colle throw InvalidArgumentException::invalidType('"explain" option', $this->options['explain'], 'boolean'); } - if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_array($this->options['hint']) && ! is_object($this->options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], 'string or array or object'); + if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $this->options['hint']); } if (isset($this->options['let']) && ! is_document($this->options['let'])) { diff --git a/src/Operation/Count.php b/src/Operation/Count.php index 9f9225942..f3d2b7eb6 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -90,8 +90,8 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::expectedDocumentType('"collation" option', $this->options['collation']); } - if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_array($this->options['hint']) && ! is_object($this->options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], 'string or array or object'); + if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $this->options['hint']); } if (isset($this->options['limit']) && ! is_integer($this->options['limit'])) { diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index 477cade91..c5826a6d9 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -26,8 +26,6 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; -use function is_array; -use function is_object; use function is_string; use function MongoDB\is_document; use function MongoDB\is_write_concern_acknowledged; @@ -96,8 +94,8 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::expectedDocumentType('"collation" option', $this->options['collation']); } - if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_array($this->options['hint']) && ! is_object($this->options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], ['string', 'array', 'object']); + if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $this->options['hint']); } if (isset($this->options['session']) && ! $this->options['session'] instanceof Session) { diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index a979df229..bd69cde11 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -91,7 +91,7 @@ public function __construct(private string $databaseName, private string $collec } if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], 'string or array or object'); + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $this->options['hint']); } if (isset($this->options['maxTimeMS']) && ! is_integer($this->options['maxTimeMS'])) { diff --git a/src/Operation/Find.php b/src/Operation/Find.php index 6516d52c9..a4a010010 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -195,8 +195,8 @@ public function __construct(private string $databaseName, private string $collec } } - if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_array($this->options['hint']) && ! is_object($this->options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], 'string or array or object'); + if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $this->options['hint']); } if (isset($this->options['limit']) && ! is_integer($this->options['limit'])) { diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index e67413b6c..07944db3d 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -151,8 +151,8 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::expectedDocumentType('"fields" option', $options['fields']); } - if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], ['string', 'array', 'object']); + if (isset($options['hint']) && ! is_string($options['hint']) && ! is_document($options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $options['hint']); } if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { diff --git a/src/Operation/Update.php b/src/Operation/Update.php index 0b47b1cc1..5d011da28 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -28,7 +28,6 @@ use function is_array; use function is_bool; -use function is_object; use function is_string; use function MongoDB\is_document; use function MongoDB\is_first_key_operator; @@ -122,8 +121,8 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } - if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], ['string', 'array', 'object']); + if (isset($options['hint']) && ! is_string($options['hint']) && ! is_document($options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $options['hint']); } if (! is_bool($options['multi'])) { diff --git a/tests/TestCase.php b/tests/TestCase.php index c8c7db09d..f15333a2e 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -250,7 +250,7 @@ protected static function getInvalidDocumentCodecValues(): array */ protected static function getInvalidHintValues(): array { - return [123, 3.14, true]; + return [123, 3.14, true, PackedArray::fromPHP(['hint'])]; } /** From ad791ec507c2dcc9fcbb757760a0ee7c6396dfd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 16 Jan 2025 09:39:01 +0100 Subject: [PATCH 2/2] Test using empty PackedArray Co-authored-by: Jeremy Mikola --- tests/TestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index f15333a2e..2b6b86eb2 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -250,7 +250,7 @@ protected static function getInvalidDocumentCodecValues(): array */ protected static function getInvalidHintValues(): array { - return [123, 3.14, true, PackedArray::fromPHP(['hint'])]; + return [123, 3.14, true, PackedArray::fromPHP([])]; } /**