I am building an API, the desired output when there is an error is as follows:
{
"success": false,
"messages" : [
{
"field is missing for example",
....
}
]
}
I have a custom request called when from the controller as follows:
public function store(CoverageValueRequest $request, CoverageValueManager $manager){
$manager->create($request);
return response()->json(['success' => $manager->isSuccessful(), 'message' => $manager->getErrorMessage()]);
}
if the CoverageValueRequest has an error it would through something similar to this:
[
{
"series.0.values.0.cells": [
"The series.0.values.0.cells field is required when none of series.0.values.0.wifi are present."
],
"series.0.values.0.wifi": [
"The series.0.values.0.wifi field is required when none of series.0.values.0.cells are present."
]
}
]
How can I modify the error outcome of the custom request to follow the first posted structure.
Thanks in advance.
All you need to do is implementing your own failedValidation method. Default is
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException($this->response(
$this->formatErrors($validator)
));
}
In fact you should rather leave this method unchanged and implement your own version of default:
protected function formatErrors(Validator $validator)
{
return $validator->getMessageBag()->toArray();
}
Related
I don't remember this is always been so freakin' hard to do in Laravel, but how to return back to form page blade.php instead of displaying the errors as JSON object on the browser?
Controller
public function create()
{
return view('view.to.form');
}
public function store(CreateModelRequest $request)
{
Model::create($request->validated());
}
// CreateModelRequest
protected function failedValidation(Validator $validator)
{
return back()->withErrors($validator);
}
I've tried countless other "solutions" as well, but no matter what,
the failed form request return raw JSON to the browser:
{
message: 'The given data was invalid',
errors: {
first_name: ['The first name field is required.'],
last_name: ['The last name field is required.'],
email: ['The email field is required.'],
},
}
}
Ok, I found one way to return back to the form but damn this is awful:
// Controller's store method
$validator = Validator::make($request->all(), [
// rules
]);
if ($validator->fails()) {
return back()->withErrors($validator->errors());
}
I'd like to extract that code into Request class but apparently we can't return a view and therefore we can't use them outside of API endpoints. Please, correct me if I'm wrong.
I am using Laravel 5.5.14 and created a request or validation with php artisan make:request CreateInviteRequest.
I want the user to not be able to invite themselves.
Is there a way to give a proper error saying "cannot be self"?
Right now I accomplished this with 'not_in:'.Auth::guard('api')->user()->id like this:
public function rules(Request $request)
{
return [
'invite_user' => ['numeric', 'exists:users,id', 'not_in:'.Auth::guard('api')->user()->id]
];
}
This gives error message The selected invite_user is invalid.
define messages
public function messages()
{
return [
'invite_user.not_in' => 'cannot be self',
];
}
You can add ID to ignore as third parameter to the exists() rule:
'invite_user' => 'numeric|exists:users,id,' . auth()->id(),
u can achieve this by Not In.
public function rules(Request $request)
{
return [
'invite_user' => 'required|email|unique:users,email',
Rule::notIn([Auth::guard('api')->user()->id]),
];
}
Currently in lumen when you use the $this->validate($request, $rules) function inside of a controller it will throw a ValidationException with error for your validation rules(if any fail of course).
However, I need to have a code for every validation rule. We can set custom messages for rules, but I need to add a unique code.
I know there's a "formatErrorsUsing" function, where you can pass a formatter. But the data returned by the passed argument to it, has already dropped the names of the rules that failed, and replaced them with their messages. I of course don't want to string check the message to determine the code that should go there.
I considered setting the message of all rules to be "CODE|This is the message" and parsing out the code, but this feels like a very hacked solution. There has to be a cleaner way right?
I've solved this for now with the following solution:
private function ruleToCode($rule) {
$map = [
'Required' => 1001,
];
if(isset($map[$rule])) {
return $map[$rule];
}
return $rule;
}
public function formatValidationErrors(Validator $validator) {
$errors = [];
foreach($validator->failed() as $field => $failed) {
foreach($failed as $rule => $params) {
$errors[] = [
'code' => $this->ruleToCode($rule),
'field' => $field,
];
}
}
return $errors;
}
Im using a form request for validation and want to customize my errors. since I have a lot of fields to validate,I want to know if it is possible to use the same error message for multiple fields that have the same validation rule.
My actual form request looks like :
class CreateServerRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'srv_prefix' => 'required|regex:/^[A-Z][-_A-Z0-9]*$/',
//20 more to go...
];
}
public function messages()
{
return [
'srv_prefix.required' => 'required.',
'srv_prefix.regex' => 'nope, bad format.'
];
}
}
I dont like the idea of adding as many lines of errors as fields (some fields may have 2 validation rules..) is there any way to tell laravel if validation rule = required then show this type of error regardless of the field ?
You can use just the validation name as the key for the message array, if you want all messages for that particular validation to be the same:
public function messages()
{
return [
'required' => 'The field :attribute is required.',
'regex' => 'nope, bad format.'
];
}
You can use :attribute as a placeholder that will be replaced with the field name, if you need that to be part of the error message. The documentation for this is in the Validation Custom Error Messages section, not in the Form Request Validation one.
In the application login I have the following code that throw ...HttpException on logging errors:
// common/models/LoginForm.php which is called from the backend SiteController actionLogin method as $model = new LoginForm();
public function loginAdmin()
{
//die($this->getUser()->getRoleValue()."hhh");
if ($this->getUser()->getRoleValue() >= ValueHelpers::getRoleValue('Admin') && $this->getUser()->getStatusValue() == ValueHelpers::getStatusValue('Active')){
if ($this->validate()){
return \Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30:0);
}
else{
throw new \yii\web\NotFoundHttpException('Incorrect Password or Username.');
}
}
else{
throw new \yii\web\ForbiddenHttpException('Insufficient privileges to access this area.');
}
}
It is working fine, but I want to customize the page the rendered with each of NotFoundHttpException and ForbiddenHttpException. I tried to search the Yii2 api to find any parameters that may define view in the construct of the object but I could not find that. So, is there any way to custom the view of the exception?
From Mihai P. (Thank you) answer, I have got this answer. I opened the file of the error class at vendor\yiisoft\yii2\web\ErrorAction.php and I have found that it has a public property for view, so, I decided to use it and hence I defined it in the error array of the actions method as follows:
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
'view' => '#common/views/error.php',
],
];
}
Finally, in common folder I had to create a new folder named views and fill it with a view file called error.php with the following simple code
<?php
$this->title = $name;
echo $name;
echo "<br>";
echo $message;
echo "<br>";
echo $exception;
The three variables in the view $name, $message and $exception are supplied from the ErrorAction object and they could be found in the last lines of that file
...
else {
return $this->controller->render($this->view ?: $this->id, [
'name' => $name,
'message' => $message,
'exception' => $exception,
]);
}
...
If you take a look here https://github.com/yiisoft/yii2-app-advanced/blob/master/frontend/controllers/SiteController.php
You can see that it uses an external action to handle the errors
/**
* #inheritdoc
*/
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
];
}
You can either create your own ErrorAction file that extends the default one and use yours instead of the default one from Yii, or just comment out that action and create a normal actionError and put it in there.