Skip to content

[9.x] Adds fluent File validation rule#43271

Merged
taylorotwell merged 4 commits into
laravel:9.xfrom
lukeraymonddowning:restrict_file_rule
Jul 21, 2022
Merged

[9.x] Adds fluent File validation rule#43271
taylorotwell merged 4 commits into
laravel:9.xfrom
lukeraymonddowning:restrict_file_rule

Conversation

@lukeraymonddowning

@lukeraymonddowning lukeraymonddowning commented Jul 19, 2022

Copy link
Copy Markdown
Contributor

Hello there!

This PR aims to provide a similar experience to the Password validation rule for file uploads. It does so by providing a fluent, extendable File rule object.

Basic usage

// Before
$request->validate([
  'file' => ['required', 'file', 'mimes:mp3,wav,aac', 'max:12287'],
  'image' => ['required', 'file', 'image', 'min:2048', 'max:12287', Rule::dimensions()->maxWidth(1000)->maxHeight(500)],
]);

// After
$request->validate([
  'file' => ['required', File::types(['mp3', 'wav', 'aac'])->smallerThan(12 * 1024)],
  'image' => ['required', File::image()->atLeast(2 * 1024)->smallerThan(12 * 1024)->dimensions(Rule::dimensions()->maxWidth(1000)->maxHeight(500))],
]);

Available methods

The following methods are available on the rule:

  • ::types: equivalent to the mimetypes and mimes rules
  • ::image: equivalent to the image rule
  • exactly: equivalent to the size rule
  • between: equivalent to the between rule
  • atLeast: equivalent to the min rule
  • atMost: equivalent to the max rule
  • largerThan: equivalent to the min rule + 1kb
  • smallerThan: equivalent to the max rule - 1kb
  • dimensions: only available after calling ::image, allows specifying Rule::dimensions() constraints

mimetypes vs mimes

When using Laravel today, you will either use mimetypes or mimes. Remembering which rule accepts which types can be cumbersome, so the File::types method accepts either mimetypes (eg: text/plain) or file extensions (eg: mp3) and will intelligently decide on the correct validation rule to use accordingly.

It's important to note that if both mimetypes and extensions are used, both mimetypes and mimes validation rules will be present in the request. As such, it is best practice to stick to one approach or the other.

Extending for custom types

Whilst the File rule only ships with the ::image method as a custom type, the rule is Macroable, allowing each application to specify more granular file permissions as required.

// AppServiceProvider
public function boot()
{
  File::macro('document', function () {
    return File::types(['doc', 'docx', 'pdf', 'txt']);
  });
}

// Usage
$request->validate([
  'cv' => ['required', File::document()->atMost(2048)]
]);

Open for discussion

I've added default and defaults methods similar to the Password rule, but there is something to be said for not including these, as the fact that the class is macroable would basically accomplish the same thing in a more granular fashion. Happy to remove those methods if you can't see a use-case for them :-)

Thanks to @nedwors and @owenvoke for ideas and feedback whilst developing this PR.

As always, thanks for all the hard work maintaining and caring for this awesome framework and community 💪

Kind Regards,
Luke

@lukeraymonddowning

Copy link
Copy Markdown
Contributor Author

I think it would be nice (and others such @olivernybroe have mentioned it) to be able to specify the unit (mb, kb) alongside the size. However, I'm thinking that it should likely be part of a follow-up PR to keep this PR's scope as small as possible.

Were this to go in, I could see a Size support class being available:

File::image()->smallerThan(Size::mb(12))->largerThan(Size::kb(512))

@mattkingshott

Copy link
Copy Markdown
Contributor

This is super cool! I actually like the idea of defining my standard file upload rules in one place and reusing them. Having a fluent object to do rather than just a PHP array is way better!

@taylorotwell taylorotwell merged commit 3598e71 into laravel:9.x Jul 21, 2022
@taylorotwell

Copy link
Copy Markdown
Member

Thanks! I simplified this a bit to just size, min, and max instead of the more verbose sizing methods.

@karyono7528

Copy link
Copy Markdown

Is it posible make combination rule in one file like this
'file' => ['required', File::types(['mp3', 'wav', 'aac'])->smallerThan(1024)->image()->atLeast(2 * 1024)->smallerThan(12 * 1024)->dimensions(Rule::dimensions()->maxWidth(1000)->maxHeight(500))],],

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants