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);
}
Related
I have a CRUD controller created via BackPack and it works correctly, but for some reason my RequestValidation says that a field is required when it has a value on it, this happens when I try to edit a line that haves all values. This "error" only occurs with the field "link".
My controller:
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Requests\ProductDocumentRequest;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
/**
* Class ProductDocumentCrudController
* #package App\Http\Controllers\Admin
* #property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class ProductDocumentCrudController 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\ProductDocument::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/product-document');
CRUD::setEntityNameStrings('product document', 'product documents');
}
/**
* 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('title');
CRUD::column('reference');
CRUD::column('original_link')->label('Archivo');
CRUD::column('machine');
CRUD::column('machine_type');
CRUD::column('date');
/**
* 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(ProductDocumentRequest::class);
CRUD::field('title');
CRUD::field('reference');
CRUD::field('link')->type('upload')->upload(true)->label('Archivo');
CRUD::field('machine');
CRUD::field('machine_type');
/**
* 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()
{
CRUD::setValidation(ProductDocumentRequest::class);
CRUD::field('title');
CRUD::field('reference');
CRUD::field('link')->type('upload')->upload(true)->label('Archivo');
CRUD::field('machine');
CRUD::field('machine_type');
}
}
My ProductDocumentRequest:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class ProductDocumentRequest 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 [
'title' => 'required|min:5|max:255',
'reference' => 'required|min:5|max:255',
'link' => 'required|mimes:pdf|max:10000',
'machine' => 'required_without:machine_type',
'machine_type' => 'required_without:machine',
];
}
/**
* 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 [
//
];
}
}
Here is a screenshot of the problem I have:
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
}
...
}
I have a resource controller called StreamController.php, that utilizes a policy called StreamPolicy.php.
In my controller, I have this:
//StreamController.php
/**
* Construct method.
*/
public function __construct()
{
$this->middleware('auth');
$this->authorizeResource(Stream::class, 'stream');
}
With above, all the RESTful endpoints is successfully "protected" using the policy.
However, I have added a new method to my controller, called documents(), like so:
//web.php
Route::get('streams/{stream}/documents', 'StreamController#documents');
//StreamController.php
/**
* Display the imported documents of the resource
*
* #return \Illuminate\Http\Response
*/
public function documents(Stream $stream)
{
return view('streams.documents', compact('stream'));
}
Now the problem is if I visit the URL:
example.com/streams/1 and I am not the owner of the stream, I get a 403 page - but if I go to:
example.com/streams/1/documents and I am not the owner of the stream, I can still access the page.
What am I doing wrong? How can I make so my policy also covers the documents() methods in my controller?
Edit:
This is my StreamPolicy.php file:
//StreamPolicy.php
namespace App\Policies;
use App\User;
use App\Stream;
use Illuminate\Auth\Access\HandlesAuthorization;
class StreamPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view the stream.
*
* #param \App\User $user
* #param \App\Stream $stream
* #return mixed
*/
public function view(User $user, Stream $stream)
{
return $user->id == $stream->user_id;
}
/**
* Determine whether the user can create streams.
*
* #param \App\User $user
* #return mixed
*/
public function create(User $user)
{
//
return true;
}
/**
* Determine whether the user can update the stream.
*
* #param \App\User $user
* #param \App\Stream $stream
* #return mixed
*/
public function update(User $user, Stream $stream)
{
//
return $user->id == $stream->user_id;
}
/**
* Determine whether the user can delete the stream.
*
* #param \App\User $user
* #param \App\Stream $stream
* #return mixed
*/
public function delete(User $user, Stream $stream)
{
//
return $user->id == $stream->user_id;
}
/**
* Determine whether the user can restore the stream.
*
* #param \App\User $user
* #param \App\Stream $stream
* #return mixed
*/
public function restore(User $user, Stream $stream)
{
//
}
/**
* Determine whether the user can permanently delete the stream.
*
* #param \App\User $user
* #param \App\Stream $stream
* #return mixed
*/
public function forceDelete(User $user, Stream $stream)
{
//
}
}
Controller.php uses "AuthorizesRequest" trait which defines below 2 methods:
trait AuthorizesRequests
{
/**
* Get the map of resource methods to ability names.
*
* #return array
*/
protected function resourceAbilityMap()
{
return [
'show' => 'view',
'create' => 'create',
'store' => 'create',
'edit' => 'update',
'update' => 'update',
'destroy' => 'delete',
];
}
/**
* Get the list of resource methods which do not have model parameters.
*
* #return array
*/
protected function resourceMethodsWithoutModels()
{
return ['index', 'create', 'store'];
}
You can override these 2 protected methods per controller basis because every controller extends Controller.php
class UserController extends Controller
{
public function __construct ()
{
$this->authorizeResource ( User::class, 'user' );
}
/**
* Get the map of resource methods to ability names.
*
* #return array
*/
protected function resourceAbilityMap()
{
return [
'show' => 'view',
'create' => 'create',
'store' => 'create',
'edit' => 'update',
'update' => 'update',
'destroy' => 'delete',
'customMethod'=>'customMethod',
'customMethodWithoutModel'=>'customMethodWithoutModel'
];
}
/**
* Get the list of resource methods which do not have model parameters.
*
* #return array
*/
protected function resourceMethodsWithoutModels()
{
return ['index', 'create', 'store','customMethodWithoutModel'];
}
Its Policy Class
class UserPolicy
{
/**
* Determine whether the user can custom method.
*
* #param \App\User $user
* #param \App\User $model
* #return mixed
*/
public function customMethod(User $user, User $model){
return true;
}
/**
* Determine whether the user can custom method without model.
*
* #param \App\User $user
* #return mixed
*/
public function customMethodWithoutModel(User $user){
return true;
}
I don't know exactly why is not working but I'm afraid that the authorizeResource method only handles the routes for the well-known resources end-points: view, create, update, delete and restore.
Later edit: Take a look in the docs to see which are the actions handled by the Resource Controllers https://laravel.com/docs/5.7/controllers#resource-controllers
What you should do is to explicitly set the authorization to the new route:
Route::get('streams/{stream}/documents', 'StreamController#documents')->middleware('can:documents,stream');
Of course, the documents method should exist on the StreamPolicy class.
OR
To authorize inside the StreamController.documents method:
public function documents(Stream $stream)
{
$this->authorize('documents', $stream);
return view('streams.documents', compact('stream'));
}
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;
}
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');