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..7be4cf1179 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image.php @@ -0,0 +1,104 @@ +, + * size?: Range, + * width?: Range, + * height?: Range, + * orientation?: string|array, + * } + */ +final class Image extends CompositeCriterion +{ + /** + * @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 + ) { + $criteria = new Criterion\LogicalAnd( + $this->buildCriteria($fieldDefIdentifier, $data) + ); + + parent::__construct($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'])) { + $criteria[] = new FileSize( + $fieldDefIdentifier, + $data['size']['min'] ?? 0, + $data['size']['max'] ?? null, + ); + } + + if (isset($data['width'])) { + $criteria[] = new Width( + $fieldDefIdentifier, + $data['width']['min'] ?? 0, + $data['width']['max'] ?? null, + ); + } + + if (isset($data['height'])) { + $criteria[] = new Height( + $fieldDefIdentifier, + $data['height']['min'] ?? 0, + $data['height']['max'] ?? null, + ); + } + + if (isset($data['orientation'])) { + $criteria[] = new Orientation( + $fieldDefIdentifier, + $data['orientation'], + ); + } + + 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..40a0652841 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image/FileSize.php @@ -0,0 +1,92 @@ +validate($minFileSize, $maxFileSize); + + $value['minFileSize'] = $minFileSize * 1024 * 1024; + $operator = Operator::GTE; + + if ($maxFileSize >= 1) { + $operator = Operator::BETWEEN; + $value['maxFileSize'] = $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' + ); + } + } +} 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..a9f02d5745 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image/Height.php @@ -0,0 +1,92 @@ +validate($minHeight, $maxHeight); + + $value['minHeight'] = $minHeight; + $operator = Operator::GTE; + + if ($maxHeight >= 1) { + $operator = Operator::BETWEEN; + $value['maxHeight'] = $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' + ); + } + } +} 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..169f7a154c --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image/MimeType.php @@ -0,0 +1,51 @@ + $format + */ + public function __construct( + string $fieldDefIdentifier, + $format + ) { + parent::__construct(null, null, $format); + + $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..9fb9bd9581 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Criterion/Image/Width.php @@ -0,0 +1,92 @@ +validate($minWidth, $maxWidth); + + $value['minWidth'] = $minWidth; + $operator = Operator::GTE; + + if ($maxWidth >= 1) { + $operator = Operator::BETWEEN; + $value['maxWidth'] = $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' + ); + } + } +} 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 @@ +