From 56184884cfb0f591324a481e5509a6386424f0c9 Mon Sep 17 00:00:00 2001 From: Tomasz Kryszan Date: Thu, 12 Oct 2023 13:47:32 +0200 Subject: [PATCH] Added image search criterions --- .../Values/Content/Query/Criterion/Image.php | 171 ++++++++++++++++++ .../Query/Criterion/Image/Dimensions.php | 116 ++++++++++++ .../Query/Criterion/Image/FileSize.php | 99 ++++++++++ .../Content/Query/Criterion/Image/Height.php | 99 ++++++++++ .../Query/Criterion/Image/MimeType.php | 51 ++++++ .../Query/Criterion/Image/Orientation.php | 104 +++++++++++ .../Content/Query/Criterion/Image/Width.php | 99 ++++++++++ src/lib/FieldType/Image/Orientation.php | 16 ++ 8 files changed, 755 insertions(+) create mode 100644 src/contracts/Repository/Values/Content/Query/Criterion/Image.php create mode 100644 src/contracts/Repository/Values/Content/Query/Criterion/Image/Dimensions.php create mode 100644 src/contracts/Repository/Values/Content/Query/Criterion/Image/FileSize.php create mode 100644 src/contracts/Repository/Values/Content/Query/Criterion/Image/Height.php create mode 100644 src/contracts/Repository/Values/Content/Query/Criterion/Image/MimeType.php create mode 100644 src/contracts/Repository/Values/Content/Query/Criterion/Image/Orientation.php create mode 100644 src/contracts/Repository/Values/Content/Query/Criterion/Image/Width.php create mode 100644 src/lib/FieldType/Image/Orientation.php diff --git a/src/contracts/Repository/Values/Content/Query/Criterion/Image.php b/src/contracts/Repository/Values/Content/Query/Criterion/Image.php new file mode 100644 index 0000000000..d8276a8901 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image.php @@ -0,0 +1,171 @@ +, + * size?: Range, + * width?: Range, + * height?: Range, + * orientation?: string|array, + * } + */ +final class Image extends CompositeCriterion +{ + public const SUPPORTED_IMAGE_SEARCH_CRITERIA = [ + 'mimeTypes', + 'size', + 'width', + 'height', + 'orientation', + ]; + + /** + * @phpstan-param ImageCriteria $data + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException + */ + public function __construct( + string $fieldDefIdentifier, + array $data + ) { + $this->validate($data); + + $criteria = new Criterion\LogicalAnd( + $this->buildCriteria($fieldDefIdentifier, $data) + ); + + parent::__construct($criteria); + } + + /** + * @phpstan-param ImageCriteria $data + * + * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException + */ + private function validate(array $data): void + { + if (empty($data)) { + throw new InvalidArgumentException( + '$data', + sprintf( + 'At least one of the supported criteria should be passed: "%s"', + implode(', ', self::SUPPORTED_IMAGE_SEARCH_CRITERIA) + ) + ); + } + + $notSupportedCriteria = array_diff( + array_keys($data), + array_merge( + self::SUPPORTED_IMAGE_SEARCH_CRITERIA, + ['fieldDefIdentifier'] + ) + ); + + if (!empty($notSupportedCriteria)) { + throw new InvalidArgumentException( + '$data', + sprintf( + 'Given criteria are not supported: "%s". Supported image criteria: "%s"', + implode(', ', $notSupportedCriteria), + implode(', ', self::SUPPORTED_IMAGE_SEARCH_CRITERIA) + ) + ); + } + } + + /** + * @phpstan-param ImageCriteria $data + * + * @return array<\Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion> + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException + */ + private function buildCriteria( + string $fieldDefIdentifier, + array $data + ): array { + $criteria = []; + + if (isset($data['mimeTypes'])) { + $criteria[] = new MimeType( + $fieldDefIdentifier, + $data['mimeTypes'] + ); + } + + if (isset($data['size'])) { + $size = $data['size']; + $criteria[] = new FileSize( + $fieldDefIdentifier, + $this->getMinValue($size), + $this->getMaxValue($size), + ); + } + + if (isset($data['width'])) { + $width = $data['width']; + $criteria[] = new Width( + $fieldDefIdentifier, + $this->getMinValue($width), + $this->getMaxValue($width) + ); + } + + if (isset($data['height'])) { + $height = $data['height']; + $criteria[] = new Height( + $fieldDefIdentifier, + $this->getMinValue($height), + $this->getMaxValue($height) + ); + } + + if (isset($data['orientation'])) { + $criteria[] = new Orientation( + $fieldDefIdentifier, + $data['orientation'] + ); + } + + return $criteria; + } + + /** + * @param array{min?: int|null} $data + */ + private function getMinValue(array $data): int + { + return $data['min'] ?? 0; + } + + /** + * @param array{max?: int|null} $data + */ + private function getMaxValue(array $data): ?int + { + return $data['max'] ?? null; + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Criterion/Image/Dimensions.php b/src/contracts/Repository/Values/Content/Query/Criterion/Image/Dimensions.php new file mode 100644 index 0000000000..6798399ad6 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image/Dimensions.php @@ -0,0 +1,116 @@ +validate($data); + + $criteria = new Criterion\LogicalAnd( + $this->buildCriteria( + $fieldDefIdentifier, + $data + ) + ); + + parent::__construct($criteria); + } + + /** + * @phpstan-param ImageDimensions $data + * + * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException + */ + private function validate(array $data): void + { + if (empty($data)) { + throw new InvalidArgumentException( + '$data', + sprintf( + 'At least one of the supported criteria should be passed: "%s"', + implode(', ', self::SUPPORTED_IMAGE_DIMENSIONS_CRITERIA) + ) + ); + } + + $notSupportedCriteria = array_diff( + array_keys($data), + self::SUPPORTED_IMAGE_DIMENSIONS_CRITERIA + ); + + if (!empty($notSupportedCriteria)) { + throw new InvalidArgumentException( + '$data', + sprintf( + 'Given criteria are not supported: "%s". Supported image criteria: "%s"', + implode(', ', $notSupportedCriteria), + implode(', ', self::SUPPORTED_IMAGE_DIMENSIONS_CRITERIA) + ) + ); + } + } + + /** + * @phpstan-param ImageDimensions $data + * + * @return array<\Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion> + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException + */ + private function buildCriteria( + string $fieldDefIdentifier, + array $data + ): array { + $criteria = []; + + if (isset($data['width'])) { + $width = $data['width']; + $criteria[] = new Width( + $fieldDefIdentifier, + $width['min'] ?? 0, + $width['max'] ?? null, + ); + } + + if (isset($data['height'])) { + $height = $data['height']; + $criteria[] = new Height( + $fieldDefIdentifier, + $height['min'] ?? 0, + $height['max'] ?? null, + ); + } + + return $criteria; + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Criterion/Image/FileSize.php b/src/contracts/Repository/Values/Content/Query/Criterion/Image/FileSize.php new file mode 100644 index 0000000000..fdd91d5fea --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image/FileSize.php @@ -0,0 +1,99 @@ +validate($minFileSize, $maxFileSize); + + $value[] = $minFileSize * 1024 * 1024; + $operator = Operator::GTE; + + if ($maxFileSize >= 1) { + $operator = Operator::BETWEEN; + $value[] = $maxFileSize * 1024 * 1024; + } + + parent::__construct( + null, + $operator, + $value + ); + + $this->fieldDefIdentifier = $fieldDefIdentifier; + } + + public function getSpecifications(): array + { + return [ + new Specifications( + Operator::BETWEEN, + Specifications::FORMAT_ARRAY, + Specifications::TYPE_INTEGER + ), + new Specifications( + Operator::GTE, + Specifications::FORMAT_ARRAY, + Specifications::TYPE_INTEGER + ), + ]; + } + + public function getFieldDefIdentifier(): string + { + return $this->fieldDefIdentifier; + } + + /** + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException + */ + private function validate( + int $minFileSize, + ?int $maxFileSize + ): void { + if ($minFileSize < 0) { + throw new InvalidArgumentException( + '$minFileSize', + 'Value should be grater or equal 0' + ); + } + + if ( + null !== $maxFileSize + && $maxFileSize < 1 + ) { + throw new InvalidArgumentException( + '$maxFileSize', + 'Value should be grater or equal 1' + ); + } + + if ($minFileSize > $maxFileSize) { + throw new InvalidArgumentException( + '$minFileSize', + 'Value should be grater than' . $maxFileSize + ); + } + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Criterion/Image/Height.php b/src/contracts/Repository/Values/Content/Query/Criterion/Image/Height.php new file mode 100644 index 0000000000..f9033a65c5 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image/Height.php @@ -0,0 +1,99 @@ +validate($minHeight, $maxHeight); + + $value[] = $minHeight; + $operator = Operator::GTE; + + if ($maxHeight >= 1) { + $operator = Operator::BETWEEN; + $value[] = $maxHeight; + } + + parent::__construct( + null, + $operator, + $value + ); + + $this->fieldDefIdentifier = $fieldDefIdentifier; + } + + public function getSpecifications(): array + { + return [ + new Specifications( + Operator::BETWEEN, + Specifications::FORMAT_ARRAY, + Specifications::TYPE_INTEGER + ), + new Specifications( + Operator::GTE, + Specifications::FORMAT_ARRAY, + Specifications::TYPE_INTEGER + ), + ]; + } + + public function getFieldDefIdentifier(): string + { + return $this->fieldDefIdentifier; + } + + /** + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException + */ + private function validate( + int $minHeight, + ?int $maxHeight + ): void { + if ($minHeight < 0) { + throw new InvalidArgumentException( + '$minHeight', + 'Value should be grater or equal 0' + ); + } + + if ( + null !== $maxHeight + && $maxHeight < 1 + ) { + throw new InvalidArgumentException( + '$maxHeight', + 'Value should be grater or equal 1' + ); + } + + if ($minHeight > $maxHeight) { + throw new InvalidArgumentException( + '$minHeight', + 'Value should be grater than' . $maxHeight + ); + } + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Criterion/Image/MimeType.php b/src/contracts/Repository/Values/Content/Query/Criterion/Image/MimeType.php new file mode 100644 index 0000000000..e8b6029636 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image/MimeType.php @@ -0,0 +1,51 @@ + $type + */ + public function __construct( + string $fieldDefIdentifier, + $type + ) { + parent::__construct(null, null, $type); + + $this->fieldDefIdentifier = $fieldDefIdentifier; + } + + public function getSpecifications(): array + { + return [ + new Specifications( + Operator::EQ, + Specifications::FORMAT_SINGLE, + Specifications::TYPE_STRING + ), + new Specifications( + Operator::IN, + Specifications::FORMAT_ARRAY, + Specifications::TYPE_STRING + ), + ]; + } + + public function getFieldDefIdentifier(): string + { + return $this->fieldDefIdentifier; + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Criterion/Image/Orientation.php b/src/contracts/Repository/Values/Content/Query/Criterion/Image/Orientation.php new file mode 100644 index 0000000000..70c504ce0f --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image/Orientation.php @@ -0,0 +1,104 @@ + $orientation + * + * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException + */ + public function __construct( + string $fieldDefIdentifier, + $orientation + ) { + $this->validate($orientation); + + parent::__construct(null, null, $orientation); + + $this->fieldDefIdentifier = $fieldDefIdentifier; + } + + public function getSpecifications(): array + { + return [ + new Specifications( + Operator::EQ, + Specifications::FORMAT_SINGLE, + Specifications::TYPE_STRING + ), + new Specifications( + Operator::IN, + Specifications::FORMAT_ARRAY, + Specifications::TYPE_STRING + ), + ]; + } + + public function getFieldDefIdentifier(): string + { + return $this->fieldDefIdentifier; + } + + /** + * @param string|array $orientation + * + * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException + */ + private function validate($orientation): void + { + if ( + is_string($orientation) + && !in_array($orientation, self::ALLOWED_ORIENTATIONS, true) + ) { + $this->throwException($orientation); + } + + if (is_array($orientation)) { + $invalidOrientations = array_filter( + $orientation, + static fn ($value): bool => !in_array($value, self::ALLOWED_ORIENTATIONS, true) + ); + + if (!empty($invalidOrientations)) { + $this->throwException(implode(', ', $invalidOrientations)); + } + } + } + + /** + * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentException + */ + private function throwException(string $whatIsWrong): void + { + throw new InvalidArgumentException( + '$orientation', + sprintf( + 'Invalid image orientation: "%s". Allowed orientations: %s', + $whatIsWrong, + implode(', ', self::ALLOWED_ORIENTATIONS) + ) + ); + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Criterion/Image/Width.php b/src/contracts/Repository/Values/Content/Query/Criterion/Image/Width.php new file mode 100644 index 0000000000..4c6b4e1715 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image/Width.php @@ -0,0 +1,99 @@ +validate($minWidth, $maxWidth); + + $value[] = $minWidth; + $operator = Operator::GTE; + + if ($maxWidth >= 1) { + $operator = Operator::BETWEEN; + $value[] = $maxWidth; + } + + parent::__construct( + null, + $operator, + $value + ); + + $this->fieldDefIdentifier = $fieldDefIdentifier; + } + + public function getSpecifications(): array + { + return [ + new Specifications( + Operator::BETWEEN, + Specifications::FORMAT_ARRAY, + Specifications::TYPE_INTEGER + ), + new Specifications( + Operator::GTE, + Specifications::FORMAT_ARRAY, + Specifications::TYPE_INTEGER + ), + ]; + } + + public function getFieldDefIdentifier(): string + { + return $this->fieldDefIdentifier; + } + + /** + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException + */ + private function validate( + int $minWidth, + ?int $maxWidth + ): void { + if ($minWidth < 0) { + throw new InvalidArgumentException( + '$minWidth', + 'Value should be grater or equal 0' + ); + } + + if ( + null !== $maxWidth + && $maxWidth < 1 + ) { + throw new InvalidArgumentException( + '$maxWidth', + 'Value should be grater or equal 1' + ); + } + + if ($minWidth > $maxWidth) { + throw new InvalidArgumentException( + '$minWidth', + 'Value should be grater than' . $maxWidth + ); + } + } +} diff --git a/src/lib/FieldType/Image/Orientation.php b/src/lib/FieldType/Image/Orientation.php new file mode 100644 index 0000000000..f77a60def3 --- /dev/null +++ b/src/lib/FieldType/Image/Orientation.php @@ -0,0 +1,16 @@ +