Re: FormBuilder Element Group Processing Solution

From: Date: Sat, 13 Dec 2003 07:52:13 +0000
Subject: Re: FormBuilder Element Group Processing Solution
Groups: php.pear.general 
Request: Send a blank email to pear-general+get-9497@lists.php.net to get a copy of this message
Hi guys, Thanks for all that input. I've considered everything and the "No date" option in the select menu was suitable for my site, so here's how I implemented it. First, take a quick look at the form screenshot to get a clearer idea of what I was trying to achieve: http://www.hyipreview.com/dev/editProgram.png Each program has an open date and a close date, either can be empty. Okay. So initally, I needed to add the "--" item at the top of the select menus. I checked out the date element class and found that it already supports this and that you can turn on the feature when creating the element. So in my Programs data object I added a preGenerateForm() : function preGenerateForm(&$inForm) { $elements = array(); foreach ($this->formDateFields as $dateField) { $dateElement =& HTML_QuickForm::createElement('date', $dateField, $this->fieldLabels[$dateField], array('format' => 'MdY', 'addEmptyOption'=>true, 'emptyOptionText'=>'--')); $elements[$dateField] = $dateElement; } $this->preDefElements = $elements; } Note the "addEmptyOption" and "emptyOptionText". Problem was, when I selected the "--" options for a date field which would result in an array of 3 null elements (day, month, year), FormBuilder would send this array to it's internal function _array2date() which would return the current date. This resulted in the dataobject being updated with the current date, I wanted it to be updated with NULL in this case. So then I created a preProcess() function in the data object (gets called before FormBuilder's processForm()): function preProcess(&$values) { foreach ($this->formDateFields as $dateField) { if (isset($values[$dateField])) { if (!$values[$dateField]['d'] && !$values[$dateField]['M'] && !$values[$dateField]['Y']) { $this->$dateField = 'NULL'; unset($values[$dateField]); // so that processForm doesn't re-process } } } } Here I was checking if all the date fields for a date element are set to "--", if so, I set the data object's value accordingly (had to use a string instead of null value because the data object didn't update that field in the database otherwise) and I unset the particular value so that FormBuilder's processForm() doesn't try to handle the field. Here I ran into another problem. Once the NULL value was stored in the database, when it came to redrawing the form the date element would display the current date even. This is even though the equivalent field in the database was set to NULL. I traced this to the date element's setValue() function. What happens is that FormBuilder's _generateForm() function would get the data object and call the setValue() function passing the equivalent data object's field as a parameter. When it got to the date field it called, essentially, setValue(null). Unfortunately, the date element interprets this to mean the current date. I think this behavior is wrong when the "addEmptyOption" is enabled otherwise there is no way to set the element's value to the empty option! So I actually went in and patched the setValue to:
    function setValue($value)
    {
        if ($this->_options['addEmptyOption'] && !$value) { //added to allow setting of empty option
       	$value = array(
                'D','l','d','M','m','F','Y','y','h','H','i','s','a','A'
                	=> $this->_options['emptyOptionValue']
            );         } elseif (!is_array($value)) { //original code
            // might be a unix epoch, then we fill all possible values
            $arr = explode('-', date('w-d-n-Y-y-h-H-i-s-a-A', (int)$value));
            $value = array(
                'D' => $arr[0],
                'l' => $arr[0],
                'd' => $arr[1],
                'M' => $arr[2],
                'm' => $arr[2],
                'F' => $arr[2],
                'Y' => $arr[3],
                'y' => $arr[3],
                'h' => $arr[4],
                'H' => $arr[5],
                'i' => $arr[6],
                's' => $arr[7],
                'a' => $arr[8],
                'A' => $arr[9]
            );
        }
        parent::setValue($value);
    }
Would it be possible to get the official code updated to include this? Finally, there was one more little bug. Since I was creating the date element manually in my preGenerateForm() function, FormBuilder, in it's _generateForm() function, decides not to check whether the field is a date field and, thus, doesn't run the date field through it's internal function _date2array() resulting in a null passed to setValue() even when the date value is set (because array isn't generated from _date2array() function.) So I fixed this in postGenerateForm() like this: function postGenerateForm(&$inForm) { foreach ($this->formDateFields as $dateField) { if ($this->$dateField) { $date = $inForm->getElement($dateField); $date->setValue($this->_date2array($this->$dateField)); } } } And I had to copy the _date2array() function into my dataobject class since FormBuilder's is protected. And then, it worked! Is there a better way? What do you think? Thanks, Orya Arnaud said:
You can also add an <option> to te select which is NULL => 'No date'. Ddding the methods
    function preGenerateForm(&$fg)
    {
    }
and/or
    function postGenerateForm(&$fg)
    {
    }
You can add elements previous to the form creation example is, it predefines some form elements
    function preGenerateForm(&$fg)
    {
        $this->fieldLabels = array(
            'nom'       => 'Nom',
            'prenom'    => 'Prénom',
            'handle'    => 'Login'
        );
        $el = array();
        $el['is_active'] =& HTML_QuickForm::createElement('select', 'is_active', 'Ce compte est-il actif ?',
          array('Y' => 'OUI',
                'N' => 'NON'
          ), array('size' => 2)
        );
            $el['fonction'] =& HTML_QuickForm::createElement('select', 'fonction', 'Fonction',
              array('employee' => 'Employee',
                    'NULL' => 'Autre'
              ), array('size' => 4)
            );
        $el['auth_user_id'] =& HTML_QuickForm::createElement('hidden', 'auth_user_id');
        $this->preDefElements = $el;
        $this->preDefOrder    = array(
            'prenom', 'nom', 'handle', 'passwd', 'email', 'telephone',
            'mobile', 'bureau', 'fonction', 'is_active',
            'lastlogin', 'auth_user_id',
            'datecrea', 'demandepass', 'lettrecache'
        );
    }
Stanislav said:
Hi, Orya, I don't use QuickForm (shame on me!), I somehow got comfortable with OOHForms after fixing some of its issues. Anyway, back in OOHForms I'd write a new element class which would only need to pick up environment variables, do its validation and be able to output itself to HTML. In Pear, I believe you can do the same by superclassing the date element. However, you might have to deal with all kinds of issues when doing this. In the end, it might not be worth it, but if you need to use this kind of date element often, and want to share it with others, it would be the best solution. Best regards, Stanislav
Markus said:
My thoughts are to create an element group containing a date value and a checkbox, if the checkbox isn't set the date selects would be disabled (via javascript.) To do this I need to 1) Add the group to the form and replace the existing date fields 2) add form processing that determines whether checkbox is on or off and determines whether to set date to NULL or not 3) write the javascript
Except for the Javascript and grouping part, this is how I've done it so far - just add a select box and simply ignore the date values if it's not set. However, the current date support in FormBuilder kinda sucks. I've been thinking about adding a more elegant solution, but I can't seem to come up with something truly general - so if anybody has ideas for this, please shoot :-) I've also been thinking about adding a new form element type to QuickForm that handles manually typed dates in textfields (not just simple validation, but also including conversion for ISO dates from a database)... this is what FormBuilder could then use as the standard element for dates...
Hi, This is my first time posting to this list, I hope I'm going about it the right way. I am in a situation where I have used FormBuilder to generate a form of which two elements are dates. Now I have defined them as such in the DataObject so they appear as pop-up selects in the HTML page. My problem is that I would like to give the possibility of not entering a date (i.e. NULL value) and I haven't figured out an efficient solution yet. My thoughts are to create an element group containing a date value and a checkbox, if the checkbox isn't set the date selects would be disabled (via javascript.) To do this I need to 1) Add the group to the form and replace the existing date fields 2) add form processing that determines whether checkbox is on or off and determines whether to set date to NULL or not 3) write the javascript Could you share with me your opinions on the best methods for accomplishing 1 and 2? For example, should I override the getForm() method or can I replace the particular elements with groups in another manner? Very much appreciated, Orya


« previous php.pear.general (#9497) next »