RFC: New Validation Component

zend-validator

#12

I’ve audited the various validators, and the majority take between 1 and 4 parameters. Of those that take more than 1, the majority have only 1 or 2 parameters that are truly optional. Validators that have multiple optional parameters are outliers within the library.

As noted earlier, too: the typical use case for creating validators is via a plugin manager or some builder that takes configuration to pass to the plugin manager. This means you have the option of providing an array of options just as you do now. Manual usage is relatively uncommon with this library; I suspect this is in part due to needing to memorize option keys, which are not documented anywhere, and which require looking at the code. Having actual constructor arguments allows users to benefit from IDE autocompletion and hinting, which should actually improve manual usage for developers.

I totally get the affinity for passing an array of options; I’ve long wanted the ability to pass named arguments in PHP. However, I think this is a case where they do not provide as much benefit as we may think.


#13

The translation ZF provides out-of-the-box is useful, I am very open and happy to change all my codebase to adapt to a better system, but don’t force the user to create a tool that do something that the framework did automatically before. A specific part of the library with a dedicated upgrade doc should be provided for message translation too.

Consistency is a big perk of ZF. I’m totally against abandoning the naming convention of XxxInterface, AbstractYyy and ZzzTrait

I see a lot of benefits in the way @matthew presented the change:

  1. As he said, you are going to use them exactly like now
  2. Validators are going to be much more easily tested and maintained, and this affect users too in the way bugs are less likely to happen and contributing become easier
  3. Understanding a validator through a factory that translates array-config to constructor parameters is easier than reading the source code of the constructor in v2

#14

Following what already done in ZF, I vote for zend-validator-csrf and zend-validator-db


#15

I have just made a few significant updates to this proposal; the highlights include:

  • The proposal now is for a new component, and not a new version of zend-validator. This provides a cleaner migration path, as users can install both side-by-side, and we do not need to maintain new interfaces in a v2 release and legacy interfaces in a v3 release.

  • The proposal now adds a Result interface, which ValidatorResult implements. This will allow for decorators.

  • ValidationFailureMessage now also composes a $code, which will allow contexts where string messages are not of interest when reporting errors (e.g., logging).

  • I’ve added a new section, “But what about…?” to cover topics that have arisen in comments or other discussions.

One other idea I will be looking at is expanding this new component to cover the features of zend-inputfilter, as we also want to apply the idea of statelessness to that component. Considering that the majority aspect of zend-inputfilter is to address validation, several of us feel that this approach could reduce some redundancy between the two components.


#16

The proposed package will initially depend on zend-validator v2, and provide
the proposed interface, classes, and traits only, with one or two existing
validators re-written to demonstrate how to write validators under the new
architecture.

I would prefer that we didn’t depend on zend-validator v2 as we’re committing to supporting every validator’s options. Are there really so many validators that we can’t get them written with a “help-wanted” label and advertising? Though maybe you’ve audited this and that commitment is not a problem?


#17

@akrabat — Depending on zend-validator v2 would allow us to ship a plugin manager that adds delegators to existing zend-validator implementations in order to return instances decorated in a LegacyValidator, which could be interesting in terms of migrations.

Alternately, we could do that aspect (the LegacyValidator implementation, and the alternate plugin manager and/or plugin manager configuration) via a separate “migration” package. If we did, however, that package would need a new release each time we ship a new release of the new component in order to remove validators that have been migrated.

I could go either way, to be honest.


#18

As discussed today, I’d also suggest not depending on zend-validator for a start, and instead have a dummy “callback validator” that we can use to see if the component/architecture is usable/useful.

Plugging in all existing validators could be as simple as requiring a package providing plugin manager config.

Yes, this means even more packages, but we can integrate/hardcode them into the new component once we know that the solution works.


#19

I’m sorry, Am I the only one dazed by the drastic turn in the naming convention that removes Interface suffix from the interfaces proposed?

Likely this was discussed and accepted in another RFC or topic and I missed it, if so I would appreciate a link to it.

If not, I feel the need to bring the attention to this point too: could we stick to ZF2 naming convention?


Interface suffix: take it or leave it?
#20

@Slamdunk We haven’t made or communicated a decision yet. However, all the latest RFCs have omitted the Interface suffix, including the now published zend-expressive-hal and zend-problem-details packages.

My own rationale for doing so is nicely summed up in this article from Mathias Verraes, where he argues that an interface, as the contract you are programming to, is a first-class citizen of your code. Implementations should indicate how they do so, or what context they do so for. While I’ve long been a proponent of the Interface suffix, when I consider developing the interface first, based on the use cases we need to accommodate, I find I agree with Mathias more and more.


Interface suffix: take it or leave it?
#21

I’ve started the repository under my own username on github at this time:

What I’ve done at this time:

  • I’m using the name zend-datavalidator, with the namespace Zend\DataValidator.
  • I’ve modified the proposed interfaces and traits to use the Interface and Trait suffixes pending a decision on how these artifacts should be named; consistency with existing components is likely more important at this time than other concerns.
  • I’ve added a ValidatorChain implementation, which relies on a ResultAggregate implementation to deliver the results. The chain only aggregates concrete validator instances, and executes them in the order in which they are attached (no container or priority awareness).
  • I’ve provided a Between validator implementation to demonstrate how validators might be written. It in turn extends an AbstractValidator implementation; this only provides some basics around failure message codes/templates, as well as a mechanism for building a validation failure result based on one or more such templates.

I’ve not written documentation yet, pending review by interested parties; use the tests to get an idea of how the component works.

My feeling at this time is that validator chains should likely be built from concrete instances. Since both validators and chains are stateless, this means that the services can be safely shared; I would expect discrete factories based on the needs of your application and/or individual data sets.


#22

Why should the Result object contain the validated value? Provide the value is not the responsibility of validators, nor of the Result object, is it ?


#23

The idea is that this will eventually be part of an input filter; in that situation, we would want access to both the filtered/normalized value and the raw value.

Additionally, encapsulating the value allows passing the result as a single message, giving the receiver access to the value as well.

Finally, having the value present allows it to be passed along with any other contextual variables to the ValidationErrorMessage instances for purposes of reporting or logging; we want to delay creation of these instances until they are requested.


#24

Retaining the value is not the responsibility of the validator, as that
makes the validator not reusable in the context of concurrent or shared
(across layers) usage due to its stateful nature.

Getting rid of the value/messages from the validator was the first step in
this design.

Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/


#25

@matthew

The current InputFilter component already retains the raw values, and the new InputFilter proposed by Bakura (which seems will be used for 3.0) retains the raw and filtered values.
We can still access to the raw values using InputFilter even if the validator result does not contain it.

When using validators without InputFilter, the raw value is passed to the validator, so the raw value is already available.

If ValidationErrorMessage instances must use the raw value, it could be passed by the validator to the ValidationErrorMessage constructor in the same way that contextual variables are.
As validators are now stateless, the raw value used to validate is a contextual variable.

@matthew, @ocramius Anyway, I understand your points of view, but we can consider not keeping the value in the result of validator.


#26

The value in the result are required to compose error messages and for
logging purposes.

Also, that’s what you’d pass to the next “layer”: a “validated result”.


#27

This is not necessarily true; it’s more than probable we will not use that code base, particularly as it made assumptions about the design of the validation component that are no longer true.

The plan at this point is for input filtering to also be stateless, and follow a similar design to this component: pass values to validate, and receive a result object back.

As @ocramius also notes, retaining the value in the result asked us to pass a single message to loggers, error handlers, etc. without requiring an additional message/argument.

I’m curious why you feel so strongly that we should not do this…


#28

It’s just a suggestion, I’m not saying that we should not do this.

It seems strange to me to retain the raw value in the validator result, as we already have access to it anyway. The exception is, as you pointed, to get the value to compose error messages, but in this case value could be part of the $this->messageVariables passed to the constructor of ValidationFailureMessage. I’m not aware about how loggers work, I don’t know if they need the value to be treated differently from other messages variables.

Anyway, I got my answer, thanks :slight_smile:


#29

We may have access to it in the scope in which the validation occurs, but that would then require passing that raw value and the result to any logger/reporter functionality. Passing only the result is far simpler.


#30

+1 about Interface and Trait suffixes: “[…] consistency with existing components is likely more important at this time than other concerns.”


#31

This change has already been made, and is reflected in the repository.