From the FluentValidation documentation I learned that I can abort validation by setting the cascade mode.
RuleFor(x => x.Surname)
.Cascade(CascadeMode.StopOnFirstFailure)
.NotNull()
.NotEqual("foo");
That way if the property Surname is null, the equality check won't be executed and a null pointer exception prevented. Further down in the documentation it is implied that this would also work not only within a rule but on a validator level as well.
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
// First set the cascade mode
CascadeMode = CascadeMode.StopOnFirstFailure;
// Rule definitions follow
RuleFor(...)
RuleFor(...)
}
}
I set the CascadeMode not inside the rule definition but for an instance of a validator. The expected behaviour would be that if the first RuleFor fails, the second RuleFor won't be evaluated but that's not the case. Regardless of previous validation errors, all rules are being evaluated.
Am I using it wrong or did I misinterpret the documentation?
According to the JeremyS' answer, I have misunderstood the purpose of the CascadeMode. It is in fact not intended to have effect on a validator level but only within a rule.
You can set CascadeMode at the global level by setting
ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure;
or at property level by
RuleFor(x => x.PropertyName)
.Cascade(CascadeMode.StopOnFirstFailure)
If you are using .NET Core you can set the cascade mode at a global level like below
.AddFluentValidation(fv =>
{
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = true;
fv.ValidatorOptions.CascadeMode = CascadeMode.Stop;
fv.RegisterValidatorsFromAssemblyContaining<Startup>();
});
Related
I have a plugin with a form where User can register, to avoid duplicate registrations I've added a custom Validator which checks if a FE user already contain the email.
//This is just the isValid method of the custom validator..
public function isValid($value): void
{
$existingUser = $this->frontendUserRepository->findByEmail($value)->getFirst();
if ($existingUser != null) {
$this->addError(
'E-mail already registered',
1592556619
);
}
}
Because of an additional double opt-in mechanism I would like to disable the new created FE user (which is created in the submit action of the registration form), so far so good.
But now my custom validator didn't find users which are disabled when try to find it by email.
So my question is, how can I tell it that he have to ignore the disabled state of the entry.
You will need to configure your repository method to ignore the disabled enable field. (See enablecolumns in TCA.)
You will need to add a custom findOneByEmail() method to your repository and configure the query accordingly:
$query = $this->createQuery();
$query->getQuerySettings()
->setIgnoreEnableFields(true)
->setEnableFieldsToBeIgnored(['disabled']);
Afterwards you can execute the query as usual which will now include disabled users:
$query
->matching($query->equals('email', $email))
->setLimit(1);
return $query->execute()->getFirst();
Notice that you should put this in a separate findOneByEmailIncludingHidden() or similar to avoid unexpected side-effects and make the special behavior of this query method clear.
(You may have noticed that findOneBy* is used here instead of findBy* since that will automatically return the first object.)
I have some doubt about safe validator.There is four case
i)I have some validation rule like below
[['name'], 'required','message' => 'You must enter name'],
In that case i want safe validation or it is enough
ii)I have some validation rule with some scenarios like below
public function scenarios()
{
return [
self::SCENARIO_INFO => ['title', 'phone'],
];
}
rule like that
[['title'], 'required','message' => 'You must enter Title','on' => 'info'],
In that case also i want safe validation or it is enough.
iii)Third case i have only public property no validation rules apply in that property,but i want that property in form user will enter.
iv)Fourth case i have only public property no validation rules apply in that property,and i don't want that property even form also,using only internally (i.e model).
In which cases the safe validation rule is must,i am new in yii so please explain easily understandable way.Thanks in advance
From the cases you have provided, it appears case# iii) will be the right situation for using safe.
For proper understanding please get your concepts clear about Safe Attributes, Massive Assignments. Refer to the links below:
http://www.yiiframework.com/doc-2.0/guide-structure-models.html#massive-assignment
http://www.yiiframework.com/doc-2.0/guide-structure-models.html#safe-attributes
I have an ASP.NET MVC3 website setup using fluent validation and ninject. The validation code is working. However, I set a break point in the validation class constructor and I noticed that when I request my view that uses the validation the constructor gets hit multiple times. Based on very basic testing it seems that the number of times the constructor is hit is equal to the number of properties that exist on the object. Has anyone else come across something similar? Or can someone shed more insight on how this type of validation works behind the scenes? -Thanks
Here is the constructor...
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
RuleFor(x => x.Id).NotNull();
RuleFor(x => x.Name).Length(0, 10);
RuleFor(x => x.Email).EmailAddress();
RuleFor(x => x.Age).InclusiveBetween(18, 60);
}
}
Here are the libraries/resources that I am using (I just got the NuGet packages and configured everything based on the info from the two links below):
http://fluentvalidation.codeplex.com/wikipage?title=mvc
https://github.com/ninject/ninject.web.mvc.fluentvalidation
I figured out how to prevent this issue. Even though this solves my issue, I would like input from others on whether there are any consequences in doing this?
So on the second link you will see instructions on how to set up Ninject.
On the second step you need to apply the "InRequestScope()" extension method. Then the constructor will only be hit once per http request that uses your validator. That obviously means that only one instance of the validator object is created per http request, which makes sense to me. I don't know if there are any consequences to using this solution?
Bind(match.InterfaceType).To(match.ValidatorType).InRequestScope();
Resurrecting this thread.
I had the same problem with SimpleInjector. My solution was include LifeTime.Scoped on the collection register.
private static void WarmUpMediatrAndFluentValidation(this Container container)
{
var allAssemblies = GetAssemblies();
container.RegisterSingleton<IMediator, Mediator>();
container.Register(typeof(IRequestHandler<,>), allAssemblies);
RegisterHandlers(container, typeof(INotificationHandler<>), allAssemblies);
RegisterHandlers(container, typeof(IRequestExceptionAction<,>), allAssemblies);
RegisterHandlers(container, typeof(IRequestExceptionHandler<,,>), allAssemblies);
//Pipeline
container.Collection.Register(typeof(IPipelineBehavior<,>), new[]
{
typeof(RequestExceptionProcessorBehavior<,>),
typeof(RequestExceptionActionProcessorBehavior<,>),
typeof(RequestPreProcessorBehavior<,>),
typeof(RequestPostProcessorBehavior<,>),
typeof(PipelineBehavior<,>)
});
container.Collection.Register(typeof(IRequestPreProcessor<>), new[] {typeof(EmptyRequestPreProcessor<>)});
container.Collection.Register(typeof(IRequestPostProcessor<,>), new[] {typeof(EmptyRequestPostProcessor<,>)});
container.Register(() => new ServiceFactory(container.GetInstance), Lifestyle.Singleton);
container.Collection.Register(typeof(IValidator<>), allAssemblies, Lifestyle.Scoped);
}
container.Collection.Register(typeof(IValidator<>), allAssemblies, Lifestyle.Scoped); <- Workers fine for me, calling only once per request.
Using #RenderSection("SectionName", false), why do I need to explicitly set the 2nd parameter to false when the Intellisense already states that the default is false?
Update:
The RTM signature of the RenderSection method is:
public HelperResult RenderSection(string name, bool required)
There also exists an override that looks like this:
public HelperResult RenderSection(string name) {
return RenderSection(name, required: true);
}
Note that this method no longer uses default parameters, instead opting for explicit overrides.
The signature of this method changed twice during the development of MVC 3 which explains why you might be seeing confusing examples.
Edit: It appears that the MVC 3 RTM documentation is incorrect and erroneously references a default value of the required parameter.
it needs to be true. You are saying that the section is optional.
#RenderSection("SectionName", true)
or
#RenderSection("SectionName", optional: true)
i'll try and be as clear as possible.
I'm working on some form validation using the wonderful kohana framework. However i have come at a crossroads and not sure whether the way i have taken is a wise choice.
Basically, i have a date selector using several select boxes (i toyed with the idea of using javascript date pickers but the select boxes proved to be more suitable for my purpose) and a date field in a database. I wanted to concatenate these select boxes into the date field so it can be checked to make sure its valid.
protected $_rules = array(
'mydate' => array(
'not_empty' => NULL,
'date' => NULL,
),
);
Now to me, it makes most sense to include the validation in the model, since that's where the data layer is in the MVC pattern, so i decided to create some class attributes named $_rules, $_filters and $_callbacks, each set as protected and with my basic rules applied. And then a function in the model that sets up a validation object using these attributes and returning it to whatever controller is calling it, then the controller can just run the validation and the job is done.
My problem comes when i want to concat these select boxes, to me it makes most sense to make a custom filter and pass in the post data, but with the filters rules and callbacks being attributes, i can't add any variables to them. My current solution is to manually add the extra filter in when the validation setup function is being run something similar to this:
public function setupValid($post) {
$this->_filters['mydatefield'] = array(
'MyClass::MyConcat' => array($post);
);
//creates a validation object and adds all the filters rules and callbacks
}
But i don't feel this is the cleanest solution, i'm probably nit picking as the solution works the way i require it to. However i'm not sure whether a filter was ever intended to do such a thing as this, or whether this should be a callback as the callback has access to the array by default, but then again callbacks are called last, which would mean i couldn't apply any rules like, 'not_empty' (not important in this case since they are pre populated select boxes, but might be in another case)
So i guess my question is, am i using filters as they were intended to be used?
I hope i've managed to explain this clearly.
Thanks
you need to keep in mind that you should only validate fields inside the $_rules that are very important to your database or business logic.
so for example if you would try to setup other form somewhere else in your app or you would provide a restfull api for your app, validation of the field 'day_field_(that_doesnt_exists_in_the_database_and_is_used_to_privide_a_better_ux_in_this_one_form)' => array('not_empty' => NULL) will give you a hard time to do that.
so i suggest you to keep your $_rules like they are now and provide some logic to your values() method:
// MODEL:
public function values($values)
{
if ( ! empty($values['day']) && ! empty($values['month']) && ! empty($values['year']))
{
$values['mydate'] = $values['year'].'-'.$values['month'].'-'.$values['day'];
}
return parent::values($values);
}
// CONTROLLER:
if ($orm->values($form['form_array'])->check())
{
$orm->save();
}
else
{
$this->template->errors = $orm->validate()->errors('validation');
}