Laravel 9: FormRequest::withValidator method throwing error - php

I have a FormRequest with the withValidator() method (which I copied exactly as it is in the Laravel documentation), but when executing the class an error is returned.
Class:
<?php
namespace App\Http\Requests\Conversation;
use Illuminate\Foundation\Http\FormRequest;
class StoreConversationRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array<string, mixed>
*/
public function rules()
{
return [
'type' => 'required|in:text,media',
'text' => 'required_if:type,text|string',
'medias' => 'required_if:type,media|array',
'medias.*' => 'file|max:5120|mimes:jpg,jpeg,png,pdf,mp3,mp4',
'phone' => 'required|numeric',
'conversation' => 'required|exists:conversations,id',
];
}
/**
* Configure the validator instance.
*
* #param \Illuminate\Validation\Validator $validator
* #return void
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
}
}
Error:
Method App\Http\Requests\Conversation\StoreConversationRequest::somethingElseIsInvalid does not exist.
I tried replacing $this with $validator but the error persists:
Method Illuminate\Validation\Validator::somethingElseIsInvalid does not exist.

I solved problem with this:
/**
* Configure the validator instance.
*
* #param \Illuminate\Validation\Validator $validator
* #return void
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
if ($validator->errors()->isNotEmpty()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
}
But I don't understand why a code in the documentation is not working.

I quite didn't get from where did you find this function:
somethingElseIsInvalid()
Try In this way:
public function withValidator( $validator )
{
if ( $validator->fails() ) {
// Handle errors
}
...
}

Related

Custom Form-Request dosen't work as expected- Backpack

I'm creating a user management in Laravel using Backpack package, the main functionallity works well, I mean, you can create new users and then log in with them and deleteor edit them. But there is an aspect that dosent works as I want it. The problem is that when you edit it you must insert a password too to save the edits, this is not correct because you can not modify the password. To solve this, following the BackPack documentation I separate the UserRequest, so now I have two: UserRequest & EditUserRequest.
Nevertheless, the form still mark as required the password field, it seems that it pass trhough the setupCreateOperation function even if I click on edit the user.
I upload some images with the code and what appears me in the screen:
UserCrudController.php
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Requests\UserRequest;
use App\Http\Requests\EditUserRequest;
use Illuminate\Support\Facades\Hash;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
/**
* Class UserCrudController
* #package App\Http\Controllers\Admin
* #property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class UserCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* #return void
*/
public function setup()
{
CRUD::setModel(\App\Models\User::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/user');
CRUD::setEntityNameStrings('user', 'users');
}
/**
* Define what happens when the List operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-list-entries
* #return void
*/
protected function setupListOperation()
{
CRUD::column('name');
CRUD::column('email');
CRUD::column('password');
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
}
/**
* Define what happens when the Create operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-create
* #return void
*/
protected function setupCreateOperation()
{
CRUD::setValidation(UserRequest::class);
//dd('setupCreateOperation');
CRUD::field('name');
CRUD::field('email');
CRUD::field('password');
/**
* Fields can be defined using the fluent syntax or array syntax:
* - CRUD::field('price')->type('number');
* - CRUD::addField(['name' => 'price', 'type' => 'number']));
*/
}
/**
* Define what happens when the Update operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-update
* #return void
*/
protected function setupUpdateOperation()
{
//dd('setupUpdateOperation');
$this->crud->setValidation(EditUserRequest::class);
$this->crud->setRequest($this->handlePasswordInput($this->crud->getRequest()));
$this->crud->unsetValidation(); // validation has already been run
$this->setupCreateOperation();
}
/**
* Handle password input fields.
*/
protected function handlePasswordInput($request)
{
// Encrypt password if specified.
if ($request->input('password')) {
//dd($request->input('password'));
$request->request->set('password', Hash::make($request->input('password')));
} else {
//si no lo mete el usuario que no lo tenga en cuenta
$request->request->remove('password');
}
return $request;
}
}
UserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required','min:5','max:255'],
'email' => ['required', 'string', 'email', 'max:255'],
'password' => ['required', 'string', 'min:8'], // This is the diference
];
}
/**
* Get the validation attributes that apply to the request.
*
* #return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* #return array
*/
public function messages()
{
return [
//
];
}
}
EditUserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class EditUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required','min:5','max:255'],
'email' => ['required', 'string', 'email', 'max:255'],
'password' => ['nullable', 'string', 'min:8'], // this is the difference
];
}
/**
* Get the validation attributes that apply to the request.
*
* #return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* #return array
*/
public function messages()
{
return [
//
];
}
}
If you call setupCreateOperation() at the end of your setupUpdateOperation() then the CreateRequest will override the UpdateRequest. What you can do instead is do that first:
protected function setupUpdateOperation()
{
$this->setupCreateOperation();
$this->crud->setValidation(EditUserRequest::class);
}

Laravel 5.3 withValidator() was executed before validation ends

/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'some_id' => ['required', 'exists:some_model,id'],
];
}
/**
* Configure the validator instance.
*
* #param \Illuminate\Validation\Validator $validator
* #return void
*/
public function withValidator(Validator $validator)
{
$validator->after(function (Validator $validator) {
if ($this->has('some_id') && Model::find($this->get('some_id'))->eloquent->isBlocked()) {
throw CustomException();
}
});
}
In Laravel docs it is written that withValidator() works after validation is completed. In my case I have a validation rule 'exists' but withValidator() is executed before that so 'exists' rule was ignored here and error is occurring.
Any suggestion to fix the issue would be really really helpful. Thanks

Class App\Http|Controllers\ValidateRegistraion does not exist

I have created a form request using php artisan make:request ValidateRegistration. It created a ValidateRegistration.php file under App\Http\Requests\ directory. After this I have made changes in the store() function of my registration controller ie UserController.php, means I have changed it
FROM
public function store(Request $request)
{
// Save the data
User::create(request(['fname','lname','phone','email','password']));
// redirect to home page
return redirect('/registration-success');
}
TO
public function store(ValidateRagistration $request)
{
// Save the data
User::create(request(['fname','lname','phone','email','password']));
// redirect to home page
return redirect('/registration-success');
}
And added use App\Http\Requests\ValidateRagistration; at the top of the UserController.php file. But when I submit the form without filling anything it shows me an error which is Class App\Http\Controllers\ValidateRegistraion does not exist
EDIT
Added UserController.php and ValidateRegistration.php files.
UserController.php
<?php
use App\Http\Requests\ValidateRegistration;
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
class UserController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
$title = "Registration";
return view('/registration', compact('title'));
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(ValidateRegistration $request)
{
//// validate requested data
//$this->validate(request(), [
// 'fname' => 'required',
// 'lname' => 'required',
// 'phone' => 'required|size:10',
// 'email' => 'required',
// 'password' => 'required'
//]);
// Save the data
User::create(request(['fname','lname','phone','email','password']));
// redirect to home page
return redirect('/registration-success');
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
ValidateRegistration.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ValidateRegistration extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return false;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'fname' => 'required',
'lname' => 'required',
'phone' => 'required|size:10',
'email' => 'required',
'password' => 'required'
];
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'fname.required' => 'Firstname is mandatoy',
'lname.required' => 'Lastname is mandatory',
'phone.required' => 'Phone is mandatory',
'phone.size' => 'Phone must be 10 digit',
'email.required' => 'Email is mandatory',
'password.required' => 'Password is mandatory',
];
}
}
spot the difference in your class names:
ValidateRagistration
ValidateRegistraion
and I'm guessing it should read ValidateRegistration, clear up typos, they will only confuse things later
at the top of UserController.php swap the positions of the namespace and use lines, namespace should always be first
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ValidateRegistration;
use Illuminate\Http\Request;
use App\User;
and ValidateRegistration.php is in your App\Http\Requests directory
in ValidateRegistration.php I modified the authorize() function. It was returning false. Changed it to true. It is working now.
From
public function authorize()
{
return false;
}
To
public function authorize()
{
return true;
}

Laravel Validation Extend Not Firing

I don't think that my validator extentions are working, but I can't fathom why.
Service Provider.
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Validator::extend('fail', function ($attribute, $value, $parameters, $validator) {
return false;
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
}
}
I know the Service Provider's boot is firing because if I dd(); inside the boot method I get output. If I add a dd(); to the extend closure function, I do not get any output.
Request
class SaveOrder extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
$rules = [
'customer_id' => 'in:' . Customer::getImplodedCurrentTeamKeys(),
'pin' => 'fail'
];
return $rules;
}
}
I know the request is validating correctly because if I change the rule to 'pin' => 'required' and don't give in put I get a fail.
Why is my custom validation rule not working?
I found my solution at the very bottom of the Laravel Validation docs page: (https://laravel.com/docs/5.4/validation)
For a rule to run even when an attribute is empty, the rule must imply that the attribute is required. To create such an "implicit" extension, use the Validator::extendImplicit() method:
By changing the method from extend to extendImplicit , my problem was solved.
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Validator::extendImplicit('fail', function ($attribute, $value, $parameters, $validator) {
return false;
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
}
}

Laravel 4.2: Troubleshooting "Target not instantiable" error

I've been stuck on this "Target not instantiable" error for the last 2-3 days and I have no idea why. Someone in the IRC #laravel chat room, yesterday, suggested using var_dump(App::make('Project\Frontend\Repo\Lead\LeadInterface')) when in Artisan's tinker interface which I've done and got this response:
class Project\Frontend\Repo\Lead\EloquentLead#798 (1) {
protected $lead =>
class Lead#809 (21) {
// bunch of info about the model etc relating to the interface and it's repo class
}
}
One of the members in #laravel pointed out that this meant the interface was instantiated which is great but then I realised this isn't the interface that I'm having a problem with.
So below is how I have things setup. The interface that's apparently not instantiated is ValidableInterface (last portion of code) and running var_dump(App::make('Project\Backend\Service\Validation\ValidableInterface'))
returns the dreaded "Target not instantiable" error.
EDIT: new LeadFormLaravelValidator( $app['validator'] ) extends AbstractLaravelValidator which implements ValidableInterface.
Am I missing some glaring problem with my code?
My service provider
<?php namespace Project\Frontend\Service\Form;
use Illuminate\Support\ServiceProvider;
use Project\Frontend\Service\Form\Lead\LeadForm;
use Project\Frontend\Service\Form\Lead\LeadFormLaravelValidator;
class FormServiceProvider extends ServiceProvider {
/**
* Register the binding
*
* #return void
*/
public function register()
{
$app = $this->app;
$app->bind('Project\Frontend\Service\Form\Lead\LeadForm', function($app)
{
return new LeadForm(
new LeadFormLaravelValidator( $app['validator'] ),
$app->make('Project\Frontend\Repo\Lead\LeadInterface')
);
});
}
}
My form class
<?php namespace Project\Frontend\Service\Form\Lead;
use Project\Backend\Service\Validation\ValidableInterface;
use Project\Frontend\Repo\Lead\LeadInterface;
class LeadForm {
/**
* Form Data
*
* #var array
*/
protected $data;
/**
* Validator
*
* #var \Project\Backend\Service\Validation\ValidableInterface
*/
protected $validator;
/**
* Lead repository
*
* #var \Project\Frontend\Repo\Lead\LeadInterface
*/
protected $lead;
public function __construct(ValidableInterface $validator, LeadInterface $lead)
{
$this->validator = $validator;
$this->lead = $lead;
}
My validation rules
<?php namespace Project\Frontend\Service\Form\Lead;
use Project\Backend\Service\Validation\AbstractLaravelValidator;
class LeadFormLaravelValidator extends AbstractLaravelValidator {
/**
* Validation rules
*
* #var Array
*/
protected $rules = array(
'name' => 'required|regex:/^[a-zA-Z-\s]+$/',
'email' => 'email',
'cell' => 'required|numeric|digits_between:10,11',
);
/**
* Validation messages
*
* #var Array
*/
protected $messages = array(
'regex' => 'The :attribute may only contain letters, dashes and spaces.',
'digits_between' => 'The :attribute must be 10 numbers long.',
);
}
My abstract validator
<?php namespace Project\Backend\Service\Validation;
use Illuminate\Validation\Factory;
abstract class AbstractLaravelValidator implements ValidableInterface {
/**
* Validator
*
* #var \Illuminate\Validation\Factory
*/
protected $validator;
/**
* Validation data key => value array
*
* #var Array
*/
protected $data = array();
/**
* Validation errors
*
* #var Array
*/
protected $errors = array();
/**
* Validation rules
*
* #var Array
*/
protected $rules = array();
/**
* Custom validation messages
*
* #var Array
*/
protected $messages = array();
public function __construct(Factory $validator)
{
$this->validator = $validator;
}
/**
* Set data to validate
*
* #return \Project\Backend\Service\Validation\AbstractLaravelValidator
*/
public function with(array $data)
{
$this->data = $data;
return $this;
}
/**
* Validation passes or fails
*
* #return Boolean
*/
public function passes()
{
$validator = $this->validator->make($this->data, $this->rules, $this->messages);
if( $validator->fails() )
{
$this->errors = $validator->messages();
return false;
}
return true;
}
/**
* Return errors, if any
*
* #return array
*/
public function errors()
{
return $this->errors;
}
}
My validator interface
<?php namespace Project\Backend\Service\Validation;
interface ValidableInterface {
/**
* Add data to validation against
*
* #param array
* #return \Project\Backend\Service\Validation\ValidableInterface $this
*/
public function with(array $input);
/**
* Test if validation passes
*
* #return boolean
*/
public function passes();
/**
* Retrieve validation errors
*
* #return array
*/
public function errors();
}
I believe the problem is $app->make('Project\Frontend\Repo\Lead\LeadInterface'). Laravel has no way of knowing what class to instantiate here. You have to tell Laravel by doing:
$app->bind('Project\Frontend\Repo\Lead\LeadInterface', 'Your\Implementation\Of\LeadInterface');
Edit
It's weird that you get that exception since you manually instantiate LeadForm and inject the LeadFormLaravelValidator. However this should probably resolve the issue:
$app->bind('Project\Backend\Service\Validation\ValidableInterface',
'Project\Frontend\Service\Form\Lead\LeadFormLaravelValidator');

Categories