Laravel controller validation Request does not exist - function

I'm using Laravel 8 validation, and what i'm trying to do is to validate a form with some input name, unique to table Sizes column "name" where it also depends on another column speciesId that the value from $request->speciesId.
The function in Controller is looks like this
public function storeSize(Request $request)
{
$validated = $request->validate(
[
'name' => [
'required', Rule::unique('sizes')->where(function ($query) {
return $query->where('speciesId', $request->speciesId);
})
],
'speciesId' => 'required'
]
);
}
already add use Illuminate\Http\Request; and use Illuminate\Validation\Rule; but still got "ErrorException Undefined variable: request".
when i'm try to var_dump($request) or echo $request->speciesID, the variable and value is present.
my question is, why the validation function doesn't recognize the Request variable?

The error occurs because inside your function call $request is not available. You need to make it available by adding use $request to function ($query):
$validated = $request->validate([
'name' => [
'required', Rule::unique('sizes')->where(function ($query) use ($request) {
return $query->where('speciesId', $request->speciesId);
})
],
'speciesId' => 'required'
]);

Related

Laravel validation with custom json respons

Quick question.
Would it be possible to changes the JSON validation response of laravel?
This is for a custom API that I am building in Laravel.
Validation process
$validation = $this->validate(
$request, [
'user_id' => 'required',
]);
The response shows up like this in json
{
"message": "The given data was invalid.",
"errors": {
"user_id": [
"The user id field is required."
],
}
}
Preferable it would become something like this.
{
"common:" [
"status": "invalid",
"message": "Param xxxx is required",
],
}
What would be the best way to changes this?
Is it even possible?
Thank you.
You can do this, and it will be reflected globally.
Navigate to below folder and use Controller.php
app/Http/Controllers
use Illuminate\Http\Request;
Write below method in Controller.php and change response as you want.
public function validate(
Request $request,
array $rules,
array $messages = [],
array $customAttributes = [])
{
$validator = $this->getValidationFactory()
->make(
$request->all(),
$rules, $messages,
$customAttributes
);
if ($validator->fails()) {
$errors = (new \Illuminate\Validation\ValidationException($validator))->errors();
throw new \Illuminate\Http\Exceptions\HttpResponseException(response()->json(
[
'status' => false,
'message' => "Some fields are missing!",
'error_code' => 1,
'errors' => $errors
], \Illuminate\Http\JsonResponse::HTTP_UNPROCESSABLE_ENTITY));
}
}
I have tried it with Laravel 5.6, maybe this is useful for you.
#Dev Ramesh solution is still perfectly valid for placing inline within your controller.
For those of you looking to abstract this logic out into a FormRequest, FormRequest has a handy override method called failedValidation. When this is hit, you can throw your own response exception, like so...
/**
* When we fail validation, override our default error.
*
* #param ValidatorContract $validator
*/
protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
{
$errors = $this->validator->errors();
throw new \Illuminate\Http\Exceptions\HttpResponseException(
response()->json([
'errors' => $errors,
'message' => 'The given data was invalid.',
'testing' => 'Whatever custom data you want here...',
], 422)
);
}
I was searching for an answer to this and I think I found a better way. There is an exception handler in a default Laravel app - \App\Exceptions\Handler - and you can override the invalidJson method:
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
class Handler extends ExceptionHandler
{
// ...
protected function invalidJson($request, ValidationException $exception)
{
$errors = [];
foreach ($exception->errors() as $field => $messages) {
foreach ($messages as $message) {
$errors[] = [
'code' => $field,
'message' => $message,
];
}
}
return response()->json([
'error' => $errors,
], $exception->status);
}
}

Validation rule unique requires at least 1 parameters. laravel 5.4

I've got problem with my laravel 5.4 I can't save the data
public function rules()
{
return [
'permission_id' => 'required|unique',
'name' => 'required',
'label' => 'required',
];
}
Error
Validation rule unique requires at least 1 parameters.
the unique rule need at least the name of ur database table.
ur rules function should be like this:
public function rules()
{
return [
'permission_id' => 'required|unique:db_table_name',
'name' => 'required',
'label' => 'required',
];
}
for more informations check laravel doc unique rule

Laravel not responding with validator errors

I validate a model
$validator = $c->validate($collection);
This is the validate function
public function validate($data){
return Validator::make($data, $this->rules());;
}
These are the rules
public function rules() {
return array([
'name' => [
'required', 'You need to choose a name for your collection.',
'unique:collections,table_name', 'A collection or collection table with this name already exists'
],
...
]);
}
I'm trying to send back a JSON response with the validator's errors, as such:
return response()->json($validator->errors(), 200);
I'm currently testing validation for the 'name' rule, and the validator is failing, as expected.
However, I'm expecting it to return that rule's message ("A collection or collection table with this name already exists")
Instead, I'm getting this returned:
My goal is to have laravel send back the error that I need, thank you in advance for any help.
edit: updated code:
Messages:
public function messages(){
return [
'name.required' => 'A name must be specified for the collection',
'name.unique' => 'A collection or collection table with this name already exists',
'name.min' => 'The collection name is too short',
'fields.*.fieldName.unique' => 'Field names must be unique',
'fields.*.fieldName.required' => 'One or more fields must be specified for the collection',
'fields.*.fieldName.not_in' => 'Illegal field name, please try another one',
'fields.*.fieldName.min' => 'The field name is too short',
'fields.*.dataType.required' => 'A data-type must be specified for fields',
'fields.*.dataType.in' => 'Illegal data-type'
];
}
public function rules() {
return array([
'name' => [
'required', 'You need to choose a name for your collection.',
'unique:collections,table_name', 'A collection or collection table
with this name already exists',
'min:2'
],
'fields.*.fieldName' =>
[
'unique' => 'Please ensure that the fields are uniquely named.',
'required' => 'You must specify a name for your fields.',
'not_in:'.implode(',', self::$illegalFieldNames),
'min:2'
],
'fields.*.dataType' =>
[
'required', 'You must specify a data type for your fields.',
'in:'.implode(',', self::$allowedDataTypes)
]
]);
}
public function validate($data){
return Validator::make($data, $this->rules(), $this->messages());
}
The validator make method takes the third parameter as the messages array. You can't mix the rules and messages like that.
public function rules()
{
return [
'name' => 'required|unique:collections,table_name'
];
}
public function messages()
{
return [
'name.required' => 'You need to choose a name for your collection',
'name.unique' => 'A collection or collection table with this name already exists',
];
}
public function validate($data)
{
return Validator::make($data, $this->rules(), $this->messages());
}
$this->rules($request, array(
'name' =>
'required|alpha_dash|min:5|max:255|unique:posts
));
use java script for revealing error
or you can use something like this .
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...
}
}

How do I replace the default auth.basic response with a JSON response?

I have a route group that looks like this:
Route::group(['prefix' => 'recipe','middleware'=>['auth.basic']], function (){
//Some things to do
});
When credentials are invalid Laravel outputs "Invalid credentials." How do I override this response with my own JSON response?
In AuthController, try this :
public function postLogin(Request $request)
{
$this->validate($request, [
'email' => 'required', 'password' => 'required',
]);
$credentials = [
'email' => $request->input('email'),
'password' => $request->input('password')
];
if (Auth::attempt($credentials, $request->has('remember')))
{
return redirect()->intended($this->redirectPath())
->with('success', 'You are successfully logged in');
}
return Response::json(array(
'success' => false,
'errors' => $this->getFailedLoginMessage(),
));
}
I just had a look at the Illuminate\Auth\SessionGuard. The method getBasicResponse() seems to be responsible for the response on a failed login attempt (with basic auth).
protected function getBasicResponse()
{
$headers = ['WWW-Authenticate' => 'Basic'];
return new Response('Invalid credentials.', 401, $headers);
}
How to actually overwrite it seems a little tricky though. You probably need to extend the SessionGuard Class and implement your own getBasicResponse() method. Thats the easy part, how to actually instantiate your own guard instead of the default one, I don't know yet.

Setting default values on create and update in yii

I am trying to update some fields in yii 1.1 using the following rules, but it is not working.
public function rules()
{
return [
['CreatedOn','default','value'=>time(),'isEmpty'=>true,'on'=>'insert'],
['CreatedBy','default','value'=>\Yii::$app->user->identity->id,'isEmpty'=>true,'on'=>'insert'],
['ModifiedOn','default','value'=>time(),'isEmpty'=>true,'on'=>'update'],
['ModifiedBy','default','value'=>\Yii::$app->user->identity->id,'isEmpty'=>true,'on'=>'update'],
];
}
I am looking to update CreatedBy and CreatedOn when inserting, and ModifiedBy and ModifiedOn when updating.
From soju's excellent answer, with Yii2:
By default, a model supports only a single scenario named default
You should therefore set the scenario manually in your controller i.e:
$model->scenario = 'insert';
You could also use when instead of on i.e:
['CreatedOn', 'default', 'value'=>time(), 'isEmpty'=>true, 'when'=>
function($model) { return $model->isNewRecord; }
],
['ModifiedOn', 'default', 'value'=>time(), 'isEmpty'=>true, 'when'=>
function($model) { return !$model->isNewRecord; }
],
An alternative to setting them in rules() would be to use beforeSave() to set them:
public function beforeSave($insert) {
if ($insert) {
$this->CreatedBy = \Yii::$app->user->identity->id;
$this->CreatedOn = time();
} else {
$this->ModifiedBy = \Yii::$app->user->identity->id;
$this->ModifiedOn = time();
}
return parent::beforeSave($insert);
}
This is the correct way to do it:
Behaviors:
public function behaviors()
{
return [
'timestamp' => [
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => 'created_on',
ActiveRecord::EVENT_BEFORE_UPDATE => 'modified_on',
ActiveRecord::EVENT_BEFORE_DELETE => 'deleted_at',
],
'value' => function () {
return date('Y-m-d H:i:s');
}
],
[
'class' => BlameableBehavior::className(),
'createdByAttribute' => 'created_by_id',
'updatedByAttribute' => 'updated_by_id',
],
];
}
If you need just a simple rule for default value, this is enough:
public function rules()
{
return [
['CreatedOn','default','value'=>time()],
['ModifiedOn','default','value'=>time(),'isEmpty'=>true],
...
]
}
The 'isEmpty'=>true option override the default isEmpty() function and returns true (it is always seen as empty) dues it is always populated with time()
For Yii2 version 2.0.8 from April 2016 I had an error with 'isEmpty'=>true because according to documentation it expects a function so you must to do like this:'isEmpty' => function ($value) {return true;}.
When you use this solution you get a value for ModifiedBy even on create and I believe that was not an intention. It is possible to write isEmpty to return true in case of an update but I simply used 'when' because it is much more readable for me. So, my solution for rules in a model was :
['CreatedBy', 'default', 'value' => Yii::$app->user->id],
['ModifiedBy', 'default', 'value' => Yii::$app->user->id,
'when' => function ($model) { return !$model->isNewRecord;}],
As a side note for this question is that for timestamps you should rely on database to fill them, CreatedOn with default value and a before update trigger for ModifiedOn.