Re: QF3.2 - 2 BC breaks with custom method!
| From: | Bertrand Mansion | Date: | Wed, 05 Nov 2003 20:58:06 +0000 |
| Subject: | Re: QF3.2 - 2 BC breaks with custom method! | ||
| References: | 1 | Groups: | php.pear.general |
| Request: | Send a blank email to pear-general+get-8789@lists.php.net to get a copy of this message | ||
<ignatius.reilly@free.fr> wrote :
> OK. I struggled to upgrade to 3.2
> The validation of custom functions seems to suffer at least two BC breaks:
>
>
> The set-up:
> ---------------------
> I had extended HTML_Quickform, and added a custom method:
> is_ok_values( $elementName, $submitValue, $format = NULL )
> this method is called back at validation time to check that an element's
> values are within an array property.
Never a good habit to extend for just a new method.
If only we had categories in PHP... :)
> To be more specific:
>
> class MyQF extends HTML_QuickForm {
>
> // This method checks that the passed values are within an array of
> acceptable values
> function is_ok_values( $elementName, $submitValue, $format = NULL ) {
> // returns TRUE if $submitValue is in the $this->ok_values[$elementName]
> array
> )
>
> // I register the is_ok_values() custom function as a method of the current
> MyQF object
> $this->registerRule( 'ok_values', 'function', 'is_ok_value',
> $this ) ;
>
> // I create an element "myElt"
> $this->addElement( 'select', 'myElt', 'select a gromit:', some
> array ) ;
>
> // I feed the ok_values property array with an array of values
> $this->ok_values['myElt'] = some array ;
> // I create a rule:
> $this->addRule( "elt", "please select a valid value",
> "ok_values" ) ;
> ...
> }
>
>
> Problem 1: "registry" implementation
> ---------------------
> The new implementation creates a registry object at the first rule
> registration (I think). This registry contains a copy of the QF object at
> this time; therefore further modifications of the QF object are not
> reflected.
> In the case above, when I add new elements, the additional "ok values"
> object property is not reflected in the registry.
> I found an (ugly) way around this problem:
>
> instead of doing
> $this->addRule( "elt", "please select a valid value",
> "ok_values" ) ;
>
> doing
> $this->rulesToAddAtValidateTime[] = '\$this->addRule( "elt", "please
> select
> a valid value", "ok_values" ) ;' ;
> and at validation time call eval() on each "differed rule"
That's a wrong assumption, the rule registry doesn't know anything about the
QuickForm object, it doesn't need to.
> Problem 2: custom methods are not any more passed the element name!!
> ---------------------------
>
> Old implementation: (Quickform.php, line 1495)
> ----
> case 'function':
> ...
> } elseif (method_exists($this, $ruleData[1])) {
> return $this->$ruleData[1]($elementName, $submitValue,
> $format);
> Very nice. All custom methods must be passed the arguments ($elementName,
> $submitValue, $format)
>
> New implementation: (Callback.php, line 61)
> ----
> function validate($value, $options = null)
> ...
> if (isset($callback[1])) {
> return call_user_func(array($callback[1], $callback[0]),
> $value, $options);
> I do not have access anymore to the element name!!
That's true, the element name is not passed anymore, but a dummy value is
passed instead (an empty string). That's the way it was for methods in
classes (unfortunately, that's not the way it was for functions, so there
was an incompatibility we had to solve).
We chose to recommend using 'callback' instead of 'function'.
1. The name is better as it supports both functions and methods
2. The element name was useless. Why would a validation function had to know
which element it is validating ? It's role is to validate, not to generate
some kind of output.
3. Compatibility between functions and methods.
4. If you want to use the PEAR Validate package, it only accepts 2
parameters, not an element name.
For BC reasons, we keep on supporting 'function' with a dummy parameter
because a lot of users probably use functions for validation, not methods.
> What would seem to be nice:
> -----------------
> 1. at each new entry in the registry object, update the copy of the current
> QF object (is this copy needed all along, BTW? I did not enquire deep
> enough)
> 2. return to the previous implementation of custom functions and methods.
> 3. even better include this kind of validation, which I find quite useful
> (ok, I read previous threads about including new validation rules...)
>
> I'd be most delighted if somebody offered a workaround to problem 2. I
> really would like to upgrade.
A clean solution to your problem that IMO doesn't need a HTML_QuickForm
subclassing (it's always expensive):
class HTML_QuickForm_Rule_InArray extends HTML_QuickForm_Rule
{
var $_okValues = array();
function HTML_QuickForm_Rule_InArray($array)
{
$this->_okValues = $array;
}
function validate($value)
{
return in_array($value, $this->_okValues);
}
function getValidationScript($options = null)
{
// Writing the javascript code should be a piece of cake
}
}
$rule = new HTML_QuickForm_Rule_InArray(array('ok', 'good', 'fine',
'perfect'));
$form->registerRule('ok_values', null, $rule);
...
$form->addRule('elt', 'Not an ok value', 'ok_values');
(Not tested)
You can even add a setOkValues() method to change those ok values on demand..
You can complexify the validate() method by adding a second argument for the
optional format that will validate against another array:
function validate($value, $arrayToUse)
{
return in_array($value, $this->_okValues[$arrayToUse]);
}
And finally, you can also have a look at addFormRule() which will probably
help you, if you don't like my solution.
Bertrand Mansion
Mamasam