|
2 | 2 |
|
3 | 3 | namespace Statamic\Fieldtypes\Assets; |
4 | 4 |
|
5 | | -use Illuminate\Contracts\Validation\Rule; |
6 | | -use Statamic\Contracts\GraphQL\CastableToValidationString; |
| 5 | +use Closure; |
| 6 | +use Illuminate\Contracts\Validation\ValidationRule; |
7 | 7 | use Statamic\Facades\Asset; |
8 | 8 | use Statamic\Statamic; |
9 | 9 | use Symfony\Component\HttpFoundation\File\UploadedFile; |
10 | 10 |
|
11 | | -class DimensionsRule implements CastableToValidationString, Rule |
| 11 | +class DimensionsRule implements ValidationRule |
12 | 12 | { |
13 | | - protected $parameters; |
14 | | - |
15 | | - public function __construct($parameters = null) |
| 13 | + public function __construct(protected $parameters) |
16 | 14 | { |
17 | | - $this->parameters = $parameters; |
| 15 | + $this->parameters = array_reduce($parameters, function ($result, $item) { |
| 16 | + [$key, $value] = array_pad(explode('=', $item, 2), 2, null); |
| 17 | + |
| 18 | + $result[$key] = $value; |
| 19 | + |
| 20 | + return $result; |
| 21 | + }); |
18 | 22 | } |
19 | 23 |
|
20 | | - /** |
21 | | - * Determine if the validation rule passes. |
22 | | - * |
23 | | - * @param string $attribute |
24 | | - * @param mixed $value |
25 | | - * @return bool |
26 | | - */ |
27 | | - public function passes($attribute, $value) |
| 24 | + public function validate(string $attribute, mixed $value, Closure $fail): void |
28 | 25 | { |
29 | | - return collect($value)->every(function ($id) { |
30 | | - if ($id instanceof UploadedFile) { |
31 | | - if (in_array($id->getMimeType(), ['image/svg+xml', 'image/svg'])) { |
32 | | - return true; |
33 | | - } |
34 | | - |
35 | | - $size = getimagesize($id->getPathname()); |
36 | | - } else { |
37 | | - if (! $asset = Asset::find($id)) { |
38 | | - return false; |
39 | | - } |
40 | | - |
41 | | - if ($asset->isSvg()) { |
42 | | - return true; |
43 | | - } |
44 | | - |
45 | | - $size = $asset->dimensions(); |
| 26 | + $size = [0, 0]; |
| 27 | + |
| 28 | + if ($value instanceof UploadedFile) { |
| 29 | + if (in_array($value->getMimeType(), ['image/svg+xml', 'image/svg'])) { |
| 30 | + return; |
46 | 31 | } |
47 | 32 |
|
48 | | - [$width, $height] = $size; |
| 33 | + $size = getimagesize($value->getPathname()); |
| 34 | + } elseif ($asset = Asset::find($value)) { |
| 35 | + if ($asset->isSvg()) { |
| 36 | + return; |
| 37 | + } |
49 | 38 |
|
50 | | - $parameters = $this->parseNamedParameters($this->parameters); |
| 39 | + $size = $asset->dimensions(); |
| 40 | + } |
51 | 41 |
|
52 | | - if ($this->failsBasicDimensionChecks($parameters, $width, $height) || |
53 | | - $this->failsRatioCheck($parameters, $width, $height)) { |
54 | | - return false; |
55 | | - } |
| 42 | + [$width, $height] = $size; |
| 43 | + if (! is_int($width) || ! is_int($height)) { |
| 44 | + $fail(__('statamic::validation.dimensions.unknown')); |
56 | 45 |
|
57 | | - return true; |
58 | | - }); |
59 | | - } |
| 46 | + return; |
| 47 | + } |
60 | 48 |
|
61 | | - /** |
62 | | - * Get the validation error message. |
63 | | - * |
64 | | - * @return string |
65 | | - */ |
66 | | - public function message() |
67 | | - { |
68 | | - return __((Statamic::isCpRoute() ? 'statamic::' : '').'validation.dimensions'); |
| 49 | + if ($message = $this->message($width, $height)) { |
| 50 | + $fail($message); |
| 51 | + } |
69 | 52 | } |
70 | 53 |
|
71 | | - /** |
72 | | - * Parse named parameters to $key => $value items. |
73 | | - * |
74 | | - * @param array $parameters |
75 | | - * @return array |
76 | | - */ |
77 | | - protected function parseNamedParameters($parameters) |
| 54 | + public function message(int $width, int $height): ?string |
78 | 55 | { |
79 | | - return array_reduce($parameters, function ($result, $item) { |
80 | | - [$key, $value] = array_pad(explode('=', $item, 2), 2, null); |
| 56 | + $invalid_ratio = $this->validateRatio($width, $height); |
| 57 | + $invalid_width = $this->validateWidth($width); |
| 58 | + $invalid_height = $this->validateHeight($height); |
| 59 | + $key = match (true) { |
| 60 | + $invalid_ratio => 'ratio', |
| 61 | + $invalid_width && $invalid_height && $invalid_width === $invalid_height => 'same', |
| 62 | + $invalid_width && $invalid_height && $invalid_width !== $invalid_height => 'different', |
| 63 | + (bool) $invalid_width => 'width', |
| 64 | + (bool) $invalid_height => 'height', |
| 65 | + default => null, |
| 66 | + }; |
| 67 | + |
| 68 | + if (! $key) { |
| 69 | + return null; |
| 70 | + } |
81 | 71 |
|
82 | | - $result[$key] = $value; |
| 72 | + $prefix = Statamic::isCpRoute() ? 'statamic::' : ''; |
| 73 | + |
| 74 | + $comparisons = [ |
| 75 | + 'min' => __("{$prefix}validation.dimensions.min"), |
| 76 | + 'max' => __("{$prefix}validation.dimensions.max"), |
| 77 | + 'exact' => __("{$prefix}validation.dimensions.exact"), |
| 78 | + ]; |
| 79 | + |
| 80 | + return __("{$prefix}validation.dimensions.{$key}", [ |
| 81 | + 'width' => $this->parameters['width'] ?? $this->parameters['min_width'] ?? $this->parameters['max_width'] ?? null, |
| 82 | + 'height' => $this->parameters['height'] ?? $this->parameters['min_height'] ?? $this->parameters['max_height'] ?? null, |
| 83 | + 'ratio' => $this->parameters['ratio'] ?? null, |
| 84 | + 'comparison' => $comparisons[$invalid_width] ?? '', |
| 85 | + 'comparison_width' => $comparisons[$invalid_width] ?? '', |
| 86 | + 'comparison_height' => $comparisons[$invalid_height] ?? '', |
| 87 | + ]); |
| 88 | + } |
83 | 89 |
|
84 | | - return $result; |
85 | | - }); |
| 90 | + public function validateWidth(int $width): ?string |
| 91 | + { |
| 92 | + return match (true) { |
| 93 | + isset($this->parameters['width']) && $this->parameters['width'] != $width => 'exact', |
| 94 | + isset($this->parameters['min_width']) && $this->parameters['min_width'] > $width => 'min', |
| 95 | + isset($this->parameters['max_width']) && $this->parameters['max_width'] < $width => 'max', |
| 96 | + default => null, |
| 97 | + }; |
86 | 98 | } |
87 | 99 |
|
88 | | - /** |
89 | | - * Test if the given width and height fail any conditions. |
90 | | - * |
91 | | - * @param array $parameters |
92 | | - * @param int $width |
93 | | - * @param int $height |
94 | | - * @return bool |
95 | | - */ |
96 | | - protected function failsBasicDimensionChecks($parameters, $width, $height) |
| 100 | + public function validateHeight(int $height): ?string |
97 | 101 | { |
98 | | - return (isset($parameters['width']) && $parameters['width'] != $width) || |
99 | | - (isset($parameters['min_width']) && $parameters['min_width'] > $width) || |
100 | | - (isset($parameters['max_width']) && $parameters['max_width'] < $width) || |
101 | | - (isset($parameters['height']) && $parameters['height'] != $height) || |
102 | | - (isset($parameters['min_height']) && $parameters['min_height'] > $height) || |
103 | | - (isset($parameters['max_height']) && $parameters['max_height'] < $height); |
| 102 | + return match (true) { |
| 103 | + isset($this->parameters['height']) && $this->parameters['height'] != $height => 'exact', |
| 104 | + isset($this->parameters['min_height']) && $this->parameters['min_height'] > $height => 'min', |
| 105 | + isset($this->parameters['max_height']) && $this->parameters['max_height'] < $height => 'max', |
| 106 | + default => null, |
| 107 | + }; |
104 | 108 | } |
105 | 109 |
|
106 | | - /** |
107 | | - * Determine if the given parameters fail a dimension ratio check. |
108 | | - * |
109 | | - * @param array $parameters |
110 | | - * @param int $width |
111 | | - * @param int $height |
112 | | - * @return bool |
113 | | - */ |
114 | | - protected function failsRatioCheck($parameters, $width, $height) |
| 110 | + public function validateRatio(int $width, int $height): bool |
115 | 111 | { |
116 | | - if (! isset($parameters['ratio'])) { |
| 112 | + if (! isset($this->parameters['ratio'])) { |
117 | 113 | return false; |
118 | 114 | } |
119 | 115 |
|
120 | 116 | [$numerator, $denominator] = array_replace( |
121 | | - [1, 1], array_filter(sscanf($parameters['ratio'], '%f/%d')) |
| 117 | + [1, 1], |
| 118 | + array_filter(sscanf($this->parameters['ratio'], '%f/%d')) |
122 | 119 | ); |
123 | 120 |
|
124 | 121 | $precision = 1 / (max($width, $height) + 1); |
125 | 122 |
|
126 | 123 | return abs($numerator / $denominator - $width / $height) > $precision; |
127 | 124 | } |
128 | | - |
129 | | - public function toGqlValidationString(): string |
130 | | - { |
131 | | - return 'dimensions:'.implode(',', $this->parameters); |
132 | | - } |
133 | 125 | } |
0 commit comments