I'm using element-ui components with VueJS. All is working great, except when I come to uploading a file using the file upload component:
Upload Controller:
<?php
namespace App\Http\Controllers\V1;
use Illuminate\Support\Facades\{Config, Log};
use Illuminate\Http\Request;
use App\Attachments as AttachmentClass;
use App\Http\Requests\AttachmentRequest;
use Facades\App\Attachments;
use App\Http\Controllers\Controller;
class AttachmentController extends Controller
{
/*
Upload a file for a given site
.................................................................. */
public function siteUpload (AttachmentRequest $request, $site_id)
{
// $this->request->file()
Log::info ('AttachmentController::fileUpload for site [' . $site_id . '] | request = ' . $request) ;
$attach = \App\Attachments::firstOrNew(['site_id' => $site_id]);
}
}
AttachmentRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class AttachmentRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return ['fileName' => 'required', 'file' => 'mimes:pdf, jpg, jpeg, bmp, png|size:5000'];
}
}
However, when I upload an image to laravel, I get the following message:
POST http://localhost:8000/api/v1/upload/site/628 422 (Unprocessable Entity)
AttachmentsPanel.vue?8cf7:57 Fail Msg: Error: 422 {"error":"you did not send the required json in the body"}
I have a Log::info in the Laravel Controller that should display the file received.
However, it doesn't even get that far. The FormRequest guard seems to be throwing a 422 fit.
The error function of the upload component has some console.log entries, this is what the file portion returns:
I've chcked under Network Tools in Chrome and JSON data is being passed.
From the above, I don't think its the form upload control- since the data get passed successfully to Laravel.
Related
I have a form request file handling my validations separate from my controller. How do i return validation errors after an api call within the controller?
//my controller
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function orders(GetOrdersRequest $request, OrderRepository $orderRepository)
{
$order = $orderRepository->allOrders($request->paginate);
return $this->sendSuccess('Orders retrieved successfully', $order);
}
In the FormRequest class there is a function called failedValidation:
protected function failedValidation(Validator $validator)
{
throw (new ValidationException($validator))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
It triggers when your validation fails. For API endpoints, this request is a bad response because it is a redirect and contains way too much information. To return a clean and
lightweight json respond, simply oerwrite the function failedValidation in your FormRequest for a matching response for your API. For example like this:
protected function failedValidation(Validator $validator)
{
$errors = $validator->errors();
$response = response()->json([
'message' => 'Invalid data send',
'details' => $errors->messages(),
], 422);
throw new HttpResponseException($response);
}
Credit to https://stackoverflow.com/a/56726819/2311074
Laravel request class returns back automatically when validation fails.
You should show your error messages in view(blade) file.
You can follow official documentation.
For API's it returns automatically a JSON response including error messages.
Basically you can do it in blade file:
#if($errors->has('email'))
<span class="error">{{ $errors->get('email') }}</span>
#endif
You will not be able to fetch the errors in that way since the FormRequest will throw an exception before the request reaches your controller in the event that there is a validation error. However, you can catch the error in the form request it self and modify the response there using the failedValidation method
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
class OrderRequest extends FormRequest
{
public function authorize()
{
//
}
public function rules()
{
//
}
public function failedValidation(Validator $validator)
{
$errors = $validator->errors(); // Here is your array of errors
throw new HttpResponseException($errors);
}
}
I think that's not possible, but you can use the prepareForValidation() method within you FormRequest and manipulate data before validate.
Even when using form request, Laravel handles validation for you automatically without you doing anything. On failed validation, an errors will be returned that you can access in your request response. response.data.errors (depending on the library you use for requests, of course) will contain the errors. For example:
errors: {
name: ["The name must be at least 2 characters"]
}
This is just a dummy example.
Do a quick test by forcing the request to fail and console log the response to see how it will show.
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.
I have a route in my API right in Laravel for an iOS app that lets you upload images that I got form this tutorial https://www.codetutorial.io/laravel-5-file-upload-storage-download/
and when I tried to upload the file it turns null.
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Fileentry;
use Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\File;
use Illuminate\Http\Response;
class FileEntryController extends Controller
{
public function add() {
$file = Request::file('filefield');
$extension = $file->getClientOriginalExtension();
Storage::disk('local')->put($file->getFilename().'.'.$extension, File::get($file));
$entry = new Fileentry();
$entry->mime = $file->getClientMimeType();
$entry->original_filename = $file->getClientOriginalName();
$entry->filename = $file->getFilename().'.'.$extension;
$entry->save();
return redirect('fileentry');
}
}
Route:
$api = app('Dingo\Api\Routing\Router');
$api->version('v1', function ($api) {
$api->post('fileentry/add',array(
'as' => 'addentry',
'uses' => 'App\Http\Controllers\FileEntryController#add'
));
}
the user doesn't interact with the web page is all through the app
Other information that maybe the cause of the problem is that i'm using Postman to upload the image to the laravel app (Method: POST, through the binary section).
Try using form-data method from postman and add a parameter as file type.
Keep in mind that the key of the parameter must be equal to the key you're trying to get in backend. In your case it is filefield
$file = Request::file('filefield');
In your html form add this attribute
enctype="multipart/form-data"
I get this error when trying to Validate my OrderForm.php. If someone followed Codecourse Shopping Cart Tutorial you may know why I get this error. Here is my code in some of my files that I think is most relevant to this error and of course the error.
Error:
Message: Class 'Respect\Validation\Validator' not found
File: PATH/cart/app/Validation/Forms/OrderForm.php
on 13
I will also post this image of my Directory Folders:
Directory Folder Image
OrderForm.php
<?php
namespace Cart\Validation\Forms;
use Respect\Validation\Validator as v;
class OrderForm
{
public static function rules()
{
return [
'email' => v::email(),
'name' => v::alpha(' '),
'address1' => v::alnum(' -'),
'address2' => v::optional(v::alnum(' -')),
'city' => v::alnum(' '),
'postal_code' => v::alnum(' '),
];
}
}
Validator.php
<?php
namespace Cart\Validation;
use Cart\Validation\Contracts\ValidatorInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
use Respect\Validation\Exceptions\NestedValidationException;
class Validator implements ValidatorInterface
{
protected $errors = [];
public function validate(Request $request, array $rules)
{
foreach ($rules as $field => $rule) {
try {
$rule->setName(ucfirst($field))->assert($request->getParam($field));
} catch (NestedValidationException $e) {
$this->errors[$field] = $e->getMessages();
}
}
$_SESSION['errors'] = $this->errors;
return $this;
}
public function fails()
{
return !empty($this->errors);
}
}
ValidatorInterface.php
<?php
namespace Cart\Validation\Contracts;
use Psr\Http\Message\ServerRequestInterface as Request;
interface ValidatorInterface
{
public function validate(Request $request, array $rules);
public function fails();
}
Edit: I just want to say that I changed:
use Respect\Validation\Validator as v;
to
use Cart\Validation\Validator as v;
And then I get a completely new error so that did that work.
It seems to me that you may be missing a dependency file such as respect/validation as some elements are installed during the video tutorials, I would recommend watching the video(s) concerning any of the validation routines, as the codecourse "Authentication with Slim 3:", installs additional addons/components with package managers such as composer, during the tutorial which may have been missed.
Well it tells you where the error is:
Message: Class 'Respect\Validation\Validator' not found
Path to that class is not valid, or that file is not on that path. I'm not completely sure but if you write it like you did use Respect\Validation\Validator as v; the final path will be current namespace plus that path Cart\Validation\Forms\Respect\Validation\Validator.
File: PATH/cart/app/Validation/Forms/OrderForm.php on 13
This second part is just were it triggered the error, on line 13 'email' => v::email(),.
Edit:
I just saw that image, the path should be use \App\Validation\Validator
I am writing a unit test in Laravel 5.0 and in my request class I am using a different bag to show the validation error messages.
I am using this in my file:
/* ExampleRequest.php */
namespace App\Http\Requests;
use App\Http\Requests\Request;
use Illuminate\Support\Facades\Auth;
class ExampleRequest extends Request {
protected $errorBag = 'otherbag';
public function rules(){
return [
'my_field' => 'required'
];
}
}
In my test file, I am testing using this:
/* ExampleTest.php */
class ExampleTest extends TestCase {
public function testPostWithoutData(){
$response = $this->call('POST', 'url/to/post',[
'my_field' => ''
]);
$this->assertSessionHasErrors('my_field');
}
}
If I run the tests, it can't get the right assert and return this problem:
Session missing error: my_field
Failed asserting that false is true.
If I take out the $errorBag attribute from the request file, I have no problems.
I can give more details as needed.
You can get an alternate bag from the session store like this:
$myBag = $this->app('session_store')->getBag('otherBag');
$this->assertTrue($myBag->any());
However, Laravel does not use an alternate bag by default, so I'm assuming you're doing something in your code to register your App\Request::$errorBag with the session handler.
I don't know if you are setting your session elsewhere but I guess you may do something like:
$this->session(['foo' => 'bar']);
Before you can assert something in session. See testing helpers section for Laravel 5.0