Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Presence verifier has not been set exception on validator rule exists #584

Closed
lasselehtinen opened this issue Mar 6, 2017 · 12 comments
Closed

Comments

@lasselehtinen
Copy link
Contributor

I am creating a manual validator like this:

$validator = Validator::make(['productNumber' => $productNumber], [
    'productNumber' => 'exists:products,product_number',
]);

The entry exists in the database, but I am getting the following error:

RuntimeException in Validator.php line 954:
Presence verifier has not been set.

in Validator.php line 954
at Validator->getPresenceVerifier() in Validator.php line 970
at Validator->getPresenceVerifierFor(null) in ValidatesAttributes.php line 559
at Validator->getExistCount(null, 'product', 'product_number', '9789510384725', array('product', 'product_number')) in ValidatesAttributes.php line 542
at Validator->validateExists('productNumber', '9789510384725', array('product', 'product_number'), object(Validator)) in Validator.php line 338
at Validator->validateAttribute('productNumber', 'Exists') in Validator.php line 253
@matt-allan
Copy link
Contributor

It's only set if it was registered manually or you enabled eloquent.

Did you uncomment $app->withEloquent()?

Alternatively you can register your own presence verifier as validation.presence in the container.

@lasselehtinen
Copy link
Contributor Author

lasselehtinen commented Mar 9, 2017

I have not enabled Eloquent since I have no use for it in this particular project. I guess I could enable it even though I might get a small performance hit.

I am not too familiar with validation internals in Laravel/Lumen. I was just wondering why this validation rule requires Eloquent anyway? The rule seems to be using the query builder syntax so I guess it is coming from somewhere else.

https://github.com/laravel/framework/blob/5.4/src/Illuminate/Validation/Rules/Exists.php

@matt-allan
Copy link
Contributor

the $app->withEloquent() method actually enables the query builder too. It's registering the DatabaseServiceProvider, which is required to use the query builder.

@lasselehtinen
Copy link
Contributor Author

lasselehtinen commented Mar 9, 2017

Hmm, you are completely sure? Because the app I am building has $app->withFacades() enabled while $app->withEloquent(); is not and the query builder works just fine.

@matt-allan
Copy link
Contributor

I guess If you resolve the query builder later it will work because Application::make checks that it has a binding and lazily registers the database service provider.

The problem is the validation service provider checks if the database service provider is already bound and skips registering the presence verifier if it's not.

So it's not going to register the presence verifier unless you make the database component at least once before using the validator.

@lasselehtinen
Copy link
Contributor Author

Thanks for the the explanation but it goes way over my expertise :) Is this considered a bug or not? For me it does not make sense to require Eloquent for a certain validation rule, even though it is database related.

@ghost
Copy link

ghost commented May 11, 2017

I had the same issue for my custom validator class in Laravel 5.4. After doing some googling, I kinda fixed it ('RuntimeException: Presence verifier has not been set.' is not bugging me anymore ) by calling 'setPresenceVerifier' method in the constructor of my custom validator class.

    function  __construct(Validator $validator)
    {
	$this->validator = $validator;
	$this->validator->setPresenceVerifier(app('validation.presence'));
    }

Unless I find any other way to fix this, I am sticking with it. Hope this may help. Thank you.

@jefersonralmeida
Copy link

jefersonralmeida commented Jan 11, 2018

It's pretty old, but I got the same problem, and found a solution. To me it's a bug on Laravel, I'm trying to find a good way to fix it and open a PR to Laravel, but it's another matter.
There is a simple workaround:
You just need to call app('db') or the DB facade (if you use facades, I don't like them), before creating the validator. In my case, I just included on my app.php:

//$app->withFacades();

//$app->withEloquent();
// Force db parse, to ensure presence validation setup
app('db');

@matt-allan
Copy link
Contributor

matt-allan commented Jan 12, 2018

Calling app('db') is essentially the same thing as enabling $app->withEloquent():

$this->make('db');

It isn't really a bug. If you have not enabled the database component Lumen can't use it for the presence verifier. You can verify that is the case by looking at the line of code I linked previously:

https://github.com/laravel/framework/blob/8a74cf931b9df281707cef973ee9fba5b18793e8/src/Illuminate/Validation/ValidationServiceProvider.php#L41

The other workaround is also doing the same thing. Resolving validation.presence forces db to resolve.

If Laravel didn't check for the db binding before registering the presence verifier it would force everyone to load the database component, even if they weren't using it.

The docs should probably be updated to state that the exists and unique rules require uncommenting $app->withEloquent().

@driesvints
Copy link
Member

You'll indeed need to uncomment the $app->withEloquent() rule. Feel free to make a PR against the docs if you think that'll be more clear 👍

@esinanturan
Copy link

esinanturan commented Oct 13, 2020

I am having same issue with lumen 8 and $app->withEloquent() enabled and any of the suggestions up did not help but validation works if I use $this->validate($request,['email'=>'unique:users']) but it gives error if I try it by dependency injecting Illuminate\Validation\Factory class, is there a bug about it ?

@matt-allan
Copy link
Contributor

@esinanturan try injecting Illuminate\Contracts\Validation\Factory instead.

The reason is, the validator is registered as validator. Lumen aliases this to Illuminate\Contracts\Validation\Factory, but it doesn't register an alias for Illuminate\Validation\Factory.

So when you try to inject Illuminate\Validation\Factory it doesn't use the container binding from the ValidationServiceProvider; instead it tries to autowire which skips the presence verifier code in the service provider.

In general it's a good idea to stick to the contracts listed in the docs. If you try injecting a class there's no guarantee that class has a container binding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants