Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 4 commits into from
Jul 21, 2022
Merged

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

merged 4 commits into from
Jul 21, 2022

Conversation

lukeraymonddowning
Copy link
Contributor

@lukeraymonddowning lukeraymonddowning commented Jul 19, 2022

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
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
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
Member

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

@karyono7528
Copy link

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