Laravel form request validation priority - php

In my Laravel 5.6 app, I have a controller with a store method:
use Intervention\Image\Facades\Image as ImageHandler;
public function store(StoreFoo $request)
{
if ($request->hasFile('image')) {
$toResize = ImageHandler::make($request->validated()->file('image')->getRealPath());
}
}
My StoreFoo class validates that the image field is an image:
public function rules()
{
return [
'image' => 'image'
];
}
I would expect that when I try to upload a file which is not an image, the validator would catch it and return an error. Instead the code inside the store method is run, which produces an "Unsupported image type" exception from Intervention.
Why does the validator not catch this beforehand, and how can I make it work this way?

Try this in your request file:
'image' => 'nullable|file|mimes:jpeg,png,jpg',
Of course, feel free to add whatever other mimes you will accept.

Related

Is there a way to upload Images using Laravel Jobs

I am trying to upload image in laravel jobs but i keep getting this error "Serialization of 'Illuminate\\Http\\UploadedFile' is not allowed"
In my controller i try to save the image to wasabi cloud and then passing it to the job by doing this
public function store(ThreadRequest $request)
{
$imageName = time().'.'.$request->attachment->extension();
$request->attachment->storeAs('public/attachments', $imageName, 'wasabi');
$this->dispatch(CreateThread::fromRequest($request, $imageName));
return redirect()->route('threads.index');
}
And then in my job i accept $imageName as attachment and did this
public function handle(): Thread
{
$thread = new Thread([
'title' => $this->title,
'body' => Purifier::clean($this->body),
'category_id' => $this->category,
]);
$thread->authoredBy($this->author);
$thread->save();
return $thread;
}
}
I tried passing the image from my controller to my job, although i know you need to save the image temp and pass it to laravel job but that's where i am confused.
Any help would be appreciated.

Testing S3 upload with Laravel Medialibrary "The current request does not have a file in a key named"

I'm writing a feature test for a simple photo upload to S3 using Laravel Medialibrary.
This is the test:
/** #test */
public function a_user_can_upload_a_photo()
{
$this->withoutExceptionHandling();
Storage::fake('s3');
$user = factory(User::class)->create();
$this->signIn($user);
$this->post( route('users.update.photo', [
$user,
'photo' => UploadedFile::fake()->image('photo.jpeg', 500, 500)->size(1000),
]));
$this->assertEquals(1, Media::all()->count());
Storage::disk('s3')->assertExists('photo.jpeg');
}
and this is the relevant part of the controller method handling the upload:
public function uploadPhoto(User $user, Request $request)
{
// ...
try {
$user->addMediaFromRequest('photo')
->preservingOriginal()
->toMediaCollection('user-photo');
} catch (\Exception $e) {
dd($e);
Log::debug('User photo upload: ' . $e);
}
return redirect(route('users.edit.profile', $user));
}
The error catched there with dd($e) is
The current request does not have a file in a key named photo
I actually can test out that the error message is true with putting right in front of the try-catch:
dd($request->has('photo')); === true
but
dd($request->hasFile('photo')); === false
So I do not attach my mock file properly as a file to the request obviously, but I can't figure out how to do that and every example around my online searches suggest doing the test the way I already do.
Any help much appreciated.
The post() method expects the url as the first argument, and the data as the second argument.
You are using the helper route() to generate the url, which expects the user you want to edit as a parameter, but you are also passing the file data as a parameter to the helper route(), instead of passing it as an argument to the post() method:
$this->post( // just one argument for the post method
route('users.update.photo', [ // and two parameters for the route helper
$user,
'photo' => UploadedFile::fake()->image('photo.jpeg', 500, 500)->size(1000),
])
);
So use this syntax to pass the file as second argument for the post() method:
$this->post(
route('users.update.photo', ['user' => $user]), // first argument
[ 'photo' => UploadedFile::fake()->image('photo.jpeg', 500, 500)->size(1000) ] // second argument
);

Call to a member function fails() on array

I have a problem with the laravel validation.
Call to a member function fails() on array
Symfony\Component\Debug\Exception\FatalThrowableError thrown with message "Call to a member function fails() on array"
Stacktrace:
`#0 Symfony\Component\Debug\Exception\FatalThrowableError in
C:\laragon\www\frontine\app\Http\Controllers\authController.php:37
public function postRegister(Request $request)
{
$query = $this->validate($request, [
'user' => 'string|required|unique:users|min:4|max:24',
'email' => 'email|string|required|unique:users',
'pass' => 'string|required|min:8',
'cpass' => 'string|required|min:8|same:pass',
'avatar' => 'image|mimes:jpeg,jpg,png|max:2048',
]);
if ($query->fails())
{
return redirect('/registrar')
->withErrors($query)
->withInput();
}
}
The error is because what the ->validate() method returns an array with the validated data when applied on the Request class. You, on the other hand, are using the ->fails() method, that is used when creating validators manually.
From the documentation:
Manually Creating Validators
If you do not want to use the validate method on the request, you may
create a validator instance manually using the Validator facade. The
make method on the facade generates a new validator instance:
use Validator; // <------
use Illuminate\Http\Request;
class PostController extends Controller
{
public function store(Request $request)
{
$validator = Validator::make($request->all(), [ // <---
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
return redirect('post/create')
->withErrors($validator)
->withInput();
}
// Store the blog post...
}
}
The ->fails() is called in the response of the Validator::make([...]) method that return a Validator instance. This class has the fails() method to be used when you try to handled the error response manually.
On the other hand, if you use the validate() method on the $request object the result will be an array containing the validated data in case the validation passes, or it will handle the error and add the error details to your response to be displayed in your view for example:
public function store(Request $request)
{
$validatedData = $request->validate([
'attribute' => 'your|rules',
]);
// I passed!
}
Laravel will handled the validation error automatically:
As you can see, we pass the desired validation rules into the validate
method. Again, if the validation fails, the proper response will
automatically be generated. If the validation passes, our controller
will continue executing normally.
What this error is telling you is that by doing $query->fails you're calling a method fails() on something (i.e. $query) that's not an object, but an array. As stated in the documentation $this->validate() returns an array of errors.
To me it looks like you've mixed a bit of the example code on validation hooks into your code.
If the validation rules pass, your code will keep executing normally;
however, if validation fails, an exception will be thrown and the
proper error response will automatically be sent back to the user. In
the case of a traditional HTTP request, a redirect response will be
generated, [...]
-Laravel Docs
The following code should do the trick. You then only have to display the errors in your view. You can read all about that, you guessed it, in... the docs.
public function postRegister(Request $request)
{
$query = $request->validate($request, [
'user' => 'string|required|unique:users|min:4|max:24',
'email' => 'email|string|required|unique:users',
'pass' => 'string|required|min:8',
'cpass' => 'string|required|min:8|same:pass',
'avatar' => 'image|mimes:jpeg,jpg,png|max:2048',
]);
}

How to check for required fields in object?

i have example object with fields
name => John
surname => Dow
job => engineer
and output form with placeholders. some required, some not.
what is best practice for check if it requred and show error with null fields?
There are multiple ways actually you can do that inside of controller method or make use of Laravels Request Classes for me I prefer to use Request Classes
look below I will list the two examples
Validate inside the controller's method
public function test(Request $request){
if($request->filled('name){
/*filled will check that name is set on the current
request and not empty*/
//Do your logic here
}
}
Second way is by using the Validator Facade inside your controller
use Validator;
class TestController{
public function test(Request $request){
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
/*continue with your logic here if the request failed on
validator test Laravel will automatically redirect back
with errors*/
}
}
Third way my favorite one personally
you can generate a Request class using this command
php artisan make:request AddBookRequest
that will generate the request class under "app/Http/Requests/AddBookRequest" , inside of any generated request class you will find two methods authorize() and rules()
in the authorized method you have to return truthy or falsy value this will detect if the current user making the request has authorization to fire this request inside of the rules method you do pretty much as you did in the Validator in the second way check the example
public function authorize(){
return true;
}
public function rules(){
return [
'title' => 'required|string',
'author_id' => 'required|integer'
];
}
then simply in your controller you can use the generated request like this
use App\Http\Requests\AddBookRequest;
public function store(AddBookRequest $request){
/* do your logic here since we uses a request class if it fails
then redirect back with errors will be automatically returned*/
}
Hope this helps you can read more about validation at
https://laravel.com/docs/5.6/validation
I think "simple is the best", just through object and check if properties exists
Ref: property_exists
Example:
if (property_exists($object, 'name')) {
//...do something for exists property
} else {
//...else
}

Api validation in laravel 5.4

Hi guys I'm working on API but I need to validate some data at backend, in this case, we only need a postman to send parameters and headers.
All is working fine now but I need more useful data in each request, Laravel has by default a Validator Form Request Validation, but I donĀ“t know how to use at API side.
I need to send the error message in JSON to Postman.
I found two options, one, make validations into a controller but seems to much code and the other make a php artisan make:request StoreObjectPost and then import the request into the controller and change the request of the store method, which one do you recommend, Ty!
You could instantiate the validator yourself like this:
$validator = Validator::make($request->all(), [
'name' => 'min:5'
]);
// then, if it fails, return the error messages in JSON format
if ($validator->fails()) {
return response()->json($validator->messages(), 200);
}
$PostData = Input::all();
$Validator = Validator::make(array(
'name' => $PostData['name']
), array(
'name' => 'required'
));
if ($Validator->fails()) { //if validator is failed
return false;
} else {
// do some thing here
}
Hope this may help you
You should override response(array $errors) method of FormRequest.
public function response(array $errors)
{
//Format your error message
if ($this->expectsJson()) {
return new JsonResponse($errors, 422);
}
return $this->redirector->to($this->getRedirectUrl())
->withInput($this->except($this->dontFlash))
->withErrors($errors, $this->errorBag);
}
I prefer the second option. We will be able to keep our controller clean that way, even when we use many validations for the data or using custom error message in the validation

Categories