I'm working on validating an image file with two different dimensions rule, it can b Icon or Banner depending on the selection of recently selected field. I'm doing this by adding a custom Rule class, here is my validation rule which works fine on Icon Only OR Banner Only
$validator = Validator::make([
'file' => $value,
], [
'file' => 'mimes:png,webp|dimensions:width=512,height=512|max:2048'
]);
$validator->validate();
now the problem is to validate the banner with a different dimension in the same field. Is there any way to add another Width & Height to this line? I've tried to add another rule under this file with the same name, but it doesn't work. Or is there any other approach to solve this problem? I've read the documentation but could not find the solution there.
Thanks in advance.
CodePudding user response:
Validation rules by default must all pass for the input to be valid. In your case you need one of the two rules to pass which is not possible via built-in validation rules. You can create your own validation rule e.g.:
php artisan make:rule DimensionRule
Then modify the generated rule:
class DimensionRule implements Rule {
public function passes($attribute, $value) {
$validator1 = Validator::make([ $attribute => $value ], [ $attribute => 'dimensions:width=512,height=512' ]);
if ($validator1->passes()) {
return true;
}
$validator2 = Validator::make([ $attribute => $value ], [ $attribute => 'dimensions:width=800,height=30' ]);
return $validator2->passes();
}
public function message()
{
return 'Dimensions must either be 512x512 or 800x30';
}
}
Then you can use this rule:
$validator = Validator::make([
'file' => $value,
], [
'file' => [ 'mimes:png,webp', new DimensionRule(), 'max:2048' ]
]);
$validator->validate();
CodePudding user response:
I would do it this way, buy running few validations in a row, and if it passes one, it should be OK. You can write more validation rules after that of course, I think only the dimensions validation should be here.
class FileUploadController extends Controller
{
/**
* Update the avatar for the user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function fileUpload(Request $request)
{
foreach ([[100, 50], [200, 150]] as $k => $dim) {
$validators[$k] = Validator::make($request->all(), [
'avatar' => "dimensions:width={$dim[0]},height={$dim[1]}"
]);
}
foreach ($validators as $validator) {
if ($validator->fails()) {
$invalid = true;
} else {
$invalid = false;
break;
}
}
if ($invalid) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
$path = Storage::putFile('public', $request->file('avatar'));
return $path;
}
}
And here is also a feature test:
class FileUploadTest extends TestCase
{
/**
* @dataProvider cases
*/
public function test_avatars_can_be_uploaded($w, $h, $shoudReturnError)
{
Storage::fake('public');
$file = UploadedFile::fake()->image('av1.jpg', $w, $h);
$response = $this->post('/file-upload', [
'avatar' => $file,
]);
if ($shoudReturnError) {
// The image dimensions are not right and it should return error
$response->assertSessionHasErrors(['avatar']);
} else {
// The image dimensions are fine and it should pass
Storage::assertExists('public/' . $file->hashName());
}
}
public function cases()
{
return [
[100, 50, $shoudReturnError = false],
[600, 850, $shoudReturnError = true],
[200, 150, $shoudReturnError = false],
[102, 50, $shoudReturnError = true],
];
}
}
I've provided cases where the validation should pass and where it should fail.
Cheers