In the interests of DRY, is there a framework / library / design pattern for specifying validation rules in one place, and having them evaluated on both the client and server sides? It seems like an obvious requirement, but I haven't come across anything like it.
To clarify: I'm not interested in server-side code that generates forms with the required javascript to validate it - I want the validation rules to be decoupled from the client and server side implementations, e.g. request the validation rules through a web-based API.
Is there anything of the sort?
Interesting question. I guess I'd set up a class with a static field to store all the rules.
It will need one function to either validate an input directly or return a validator function to be used on server side, and another to be accessed by ajax to get the list of rules which will be tested in javascript with eval.
Theres no reason $rulesPHP
and rulesJS
have to be the same. In fact, I don't really see the point in validating the same thing on each end - you might want to validate different things.
class Validation
{
protected static $rulesPHP =
array(
'positiveInteger' => array('($x === int($x))', '($x > 0)'),
'alphanumericString' => array(....)
);
protected static $rulesJS =
array(
'positiveInteger' => array('(x === int(x))', '(x > 0)'),
'alphanumericString' =>array(..... )
);
public static getValidatorPHP($type)
{
if (!isset($rulesPHP[$type])) return false;
$exp = explode(' && ', self::$rulesPHP[$type]);
return function($x) use ($exp)
{
return eval($exp);
};
}
public static getJsRules($type)
{
if (!isset($rulesJS[$type])) return false;
$exp = explode(' && ', self::$rulesJS[$type]);
return $exp;
}
}
used in another file by:
$posIntValidator = Validation::getValidatorPHP('positiveInteger');
$posIntValidator($_POST['text1']);
Ajax with ruleaccessor.php:
$t = $_GET['type'];
$out = Validation::getJsRules($t);
echo $out;
javascript:
function getValidator(type)
{
var rules;
$.get('/ruleaccessor.php?type=' + type, function(in) {rules = in;});
return function(x){return eval(rules);};
}
validatePosInt = getValidator('positiveInteger');
validatePosInt($('#text1').val());
Of course you'll have to decide how you want to handle things that don't validate. And if you want to have different messages for different validation errors you'll have to store a message along with each rule and wont be able to simply explode them together.
This is far from a developed idea, but hopefully the general design can get you somewhere.
Nice question!
I have done some MVC validation that gets the rules from database definition. Taking from that experience I would create a handler that takes a column specification string "namespace.table.column" and returns a set of rules to validate, preferably in JSON. Then use css classes to denote the input elements that will be validated (1) and set a validation event on all the ".validate" elements with JQuery, passing the validation object to that function.
Note that with this approach you would have to do some server side rendering of the rules, to not have to expose your database structure in javascript!
(1):
<input type="text" id="name" class="validate" />
The validation object:
perhaps start with some basic type checks, moving on with size checks?
JSON structure: validationObject =
{
type: 'integer',
length: '4',
min: '0',
max: '10000'
}
function validate(input) {
var validation = getValidationObject(); // Ajax call
// perform type check
// perform length check
// perform min/max/disallowed content checks
}
Not elaborated enough, but something in this direction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With