Improved array support for Zend_Form

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
21 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Improved array support for Zend_Form

weierophinney
Administrator
I've committed some changes to Zend_Form this afternoon that make using
arrays -- including nested arrays -- seamless for setting values,
getting values, validation, and display. However, I need to show how it
works. :-)

First off, there's now a toggle, setElementsInArray(). When you set
this on a sub form, it will automatically set the array name to the sub
form name (unless setElementsBelongTo() has already been called). This
will allow you to quickly and easily namespace the elements in subforms.

Second, you can now do nested arrays, if you follow the appropriate
steps.  The trick is that for each level of the form, you need to set
the elementBelongsTo property to mimic what array element you're using.
So, in the sample I'll outline below, if you want to namespace the
toplevel in 'foobar', and another subform would be in the 'baz'
element of that array, you'd set the subform's elementsBelongTo property
to 'foobar[baz]' --- and so on, down the tree (I show an additional
level in the example).

The best part? if you don't need this feature, everything continues to
work as it has. :-)

Without further ado, here's a sample form I've been working with:

    $form = new Zend_Form();
    $form->setElementsBelongTo('foobar')
         ->setTranslator($translate);

    $form->addElement('text', 'firstName')
         ->getElement('firstName')
         ->setLabel('First Name')
         ->setRequired(true);
           
    $form->addElement('text', 'lastName')
         ->getElement('lastName')
         ->setLabel('Last Name')
         ->setRequired(true);
           
    $subForm = new Zend_Form_SubForm();
    $subForm->setElementsBelongTo('foobar[baz]');
    $subForm->addElement('text', 'email')
            ->getElement('email')
            ->setLabel('Email Address');

    $subSubForm = new Zend_Form_SubForm();
    $subSubForm->setElementsBelongTo('foobar[baz][bat]');
    $subSubForm->addElement('checkbox', 'home')
               ->getElement('home')
               ->setLabel('Home address?');
    $subForm->addSubForm($subSubForm, 'subSub');
           
    $form->addSubForm($subForm, 'sub')
        ->addElement('submit', 'save', array('value' => 'submit'))
        ->setView($view);
           
    echo $form, "\n\n";

    $data = array('foobar' => array(
        'firstName' => 'Mabel',
        'lastName'  => 'Cow',
        'baz'    => array(
            'email' => '[hidden email]',
            'bat'   => array(
                'home' => 1,
            )
        )
    ));

    echo "Data validating:\n", var_export($data, 1), "\n\n";
    echo "Result: ", var_export($form->isValid($data), 1), "\n\n";
    echo "Retrieved values:\n", var_export($form->getValues()), "\n";

Let's look at some sample output. First, the firstName element:
   
    <dt><label for="foobar-firstName" class="required">First Name</label></dt>
    <dd>
        <input type="text" name="foobar[firstName]" id="foobar-firstName" value="" />
    </dd>

Notice that the name and ID are properly formatted; this was working
before. now let's look at the 'email' element:

    <dt><label for="foobar-baz-email" class="optional">Email Address</label></dt>
    <dd>
        <input type="text" name="foobar[baz][email]" id="foobar-baz-email" value="" />
    </dd>

Notice that this is now in a *SUBARRAY*! Guess what? it works for
arbitrary depth -- look at the 'home' element:

    <dt><label for="foobar-baz-bat-home" class="optional">Home address?</label></dt>
    <dd>
        <input type="hidden" name="foobar[baz][bat][home]" value="0"
        /><input type="checkbox" name="foobar[baz][bat][home]"
        id="foobar-baz-bat-home" value="1"  />
    </dd>

(Yes, I know there's an issue with checkboxes... ignore that for now.)

Now, what about retrieving values? The fun part is that the returned
values will mimic exactly the array I pass in (except that the returned
values will also contain the 'save' element).

If you're using array notation in forms, please give this a test, and
let me know your mileage.

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

Eric Coleman-3
Where is your amazon wish list :-d
On Feb 8, 2008, at 4:56 PM, Matthew Weier O'Phinney wrote:

> I've committed some changes to Zend_Form this afternoon that make  
> using
> arrays -- including nested arrays -- seamless for setting values,
> getting values, validation, and display. However, I need to show how  
> it
> works. :-)
>
> First off, there's now a toggle, setElementsInArray(). When you set
> this on a sub form, it will automatically set the array name to the  
> sub
> form name (unless setElementsBelongTo() has already been called). This
> will allow you to quickly and easily namespace the elements in  
> subforms.
>
> Second, you can now do nested arrays, if you follow the appropriate
> steps.  The trick is that for each level of the form, you need to set
> the elementBelongsTo property to mimic what array element you're  
> using.
> So, in the sample I'll outline below, if you want to namespace the
> toplevel in 'foobar', and another subform would be in the 'baz'
> element of that array, you'd set the subform's elementsBelongTo  
> property
> to 'foobar[baz]' --- and so on, down the tree (I show an additional
> level in the example).
>
> The best part? if you don't need this feature, everything continues to
> work as it has. :-)
>
> Without further ado, here's a sample form I've been working with:
>
>    $form = new Zend_Form();
>    $form->setElementsBelongTo('foobar')
>         ->setTranslator($translate);
>
>    $form->addElement('text', 'firstName')
>         ->getElement('firstName')
>         ->setLabel('First Name')
>         ->setRequired(true);
>
>    $form->addElement('text', 'lastName')
>         ->getElement('lastName')
>         ->setLabel('Last Name')
>         ->setRequired(true);
>
>    $subForm = new Zend_Form_SubForm();
>    $subForm->setElementsBelongTo('foobar[baz]');
>    $subForm->addElement('text', 'email')
>            ->getElement('email')
>            ->setLabel('Email Address');
>
>    $subSubForm = new Zend_Form_SubForm();
>    $subSubForm->setElementsBelongTo('foobar[baz][bat]');
>    $subSubForm->addElement('checkbox', 'home')
>               ->getElement('home')
>               ->setLabel('Home address?');
>    $subForm->addSubForm($subSubForm, 'subSub');
>
>    $form->addSubForm($subForm, 'sub')
>        ->addElement('submit', 'save', array('value' => 'submit'))
>        ->setView($view);
>
>    echo $form, "\n\n";
>
>    $data = array('foobar' => array(
>        'firstName' => 'Mabel',
>        'lastName'  => 'Cow',
>        'baz'    => array(
>            'email' => '[hidden email]',
>            'bat'   => array(
>                'home' => 1,
>            )
>        )
>    ));
>
>    echo "Data validating:\n", var_export($data, 1), "\n\n";
>    echo "Result: ", var_export($form->isValid($data), 1), "\n\n";
>    echo "Retrieved values:\n", var_export($form->getValues()), "\n";
>
> Let's look at some sample output. First, the firstName element:
>
>    <dt><label for="foobar-firstName" class="required">First Name</
> label></dt>
>    <dd>
>        <input type="text" name="foobar[firstName]" id="foobar-
> firstName" value="" />
>    </dd>
>
> Notice that the name and ID are properly formatted; this was working
> before. now let's look at the 'email' element:
>
>    <dt><label for="foobar-baz-email" class="optional">Email Address</
> label></dt>
>    <dd>
>        <input type="text" name="foobar[baz][email]" id="foobar-baz-
> email" value="" />
>    </dd>
>
> Notice that this is now in a *SUBARRAY*! Guess what? it works for
> arbitrary depth -- look at the 'home' element:
>
>    <dt><label for="foobar-baz-bat-home" class="optional">Home  
> address?</label></dt>
>    <dd>
>        <input type="hidden" name="foobar[baz][bat][home]" value="0"
>        /><input type="checkbox" name="foobar[baz][bat][home]"
>        id="foobar-baz-bat-home" value="1"  />
>    </dd>
>
> (Yes, I know there's an issue with checkboxes... ignore that for now.)
>
> Now, what about retrieving values? The fun part is that the returned
> values will mimic exactly the array I pass in (except that the  
> returned
> values will also contain the 'save' element).
>
> If you're using array notation in forms, please give this a test, and
> let me know your mileage.
>
> --
> Matthew Weier O'Phinney
> PHP Developer            | [hidden email]
> Zend - The PHP Company   | http://www.zend.com/

Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

weierophinney
Administrator
-- Eric Coleman <[hidden email]> wrote
(on Friday, 08 February 2008, 05:09 PM -0500):
> Where is your amazon wish list :-d

Well, since you ask:

    http://www.amazon.com/gp/registry/wishlist/2QTBCLSUCD8RY

;-)

But really, I just enjoy doing this stuff. :-)

I take it this worked for you?

> On Feb 8, 2008, at 4:56 PM, Matthew Weier O'Phinney wrote:
>
>> I've committed some changes to Zend_Form this afternoon that make using
>> arrays -- including nested arrays -- seamless for setting values,
>> getting values, validation, and display. However, I need to show how it
>> works. :-)
>>
>> First off, there's now a toggle, setElementsInArray(). When you set
>> this on a sub form, it will automatically set the array name to the sub
>> form name (unless setElementsBelongTo() has already been called). This
>> will allow you to quickly and easily namespace the elements in subforms.
>>
>> Second, you can now do nested arrays, if you follow the appropriate
>> steps.  The trick is that for each level of the form, you need to set
>> the elementBelongsTo property to mimic what array element you're using.
>> So, in the sample I'll outline below, if you want to namespace the
>> toplevel in 'foobar', and another subform would be in the 'baz'
>> element of that array, you'd set the subform's elementsBelongTo property
>> to 'foobar[baz]' --- and so on, down the tree (I show an additional
>> level in the example).
>>
>> The best part? if you don't need this feature, everything continues to
>> work as it has. :-)
>>
>> Without further ado, here's a sample form I've been working with:
>>
>>    $form = new Zend_Form();
>>    $form->setElementsBelongTo('foobar')
>>         ->setTranslator($translate);
>>
>>    $form->addElement('text', 'firstName')
>>         ->getElement('firstName')
>>         ->setLabel('First Name')
>>         ->setRequired(true);
>>
>>    $form->addElement('text', 'lastName')
>>         ->getElement('lastName')
>>         ->setLabel('Last Name')
>>         ->setRequired(true);
>>
>>    $subForm = new Zend_Form_SubForm();
>>    $subForm->setElementsBelongTo('foobar[baz]');
>>    $subForm->addElement('text', 'email')
>>            ->getElement('email')
>>            ->setLabel('Email Address');
>>
>>    $subSubForm = new Zend_Form_SubForm();
>>    $subSubForm->setElementsBelongTo('foobar[baz][bat]');
>>    $subSubForm->addElement('checkbox', 'home')
>>               ->getElement('home')
>>               ->setLabel('Home address?');
>>    $subForm->addSubForm($subSubForm, 'subSub');
>>
>>    $form->addSubForm($subForm, 'sub')
>>        ->addElement('submit', 'save', array('value' => 'submit'))
>>        ->setView($view);
>>
>>    echo $form, "\n\n";
>>
>>    $data = array('foobar' => array(
>>        'firstName' => 'Mabel',
>>        'lastName'  => 'Cow',
>>        'baz'    => array(
>>            'email' => '[hidden email]',
>>            'bat'   => array(
>>                'home' => 1,
>>            )
>>        )
>>    ));
>>
>>    echo "Data validating:\n", var_export($data, 1), "\n\n";
>>    echo "Result: ", var_export($form->isValid($data), 1), "\n\n";
>>    echo "Retrieved values:\n", var_export($form->getValues()), "\n";
>>
>> Let's look at some sample output. First, the firstName element:
>>
>>    <dt><label for="foobar-firstName" class="required">First
>> Name</label></dt>
>>    <dd>
>>        <input type="text" name="foobar[firstName]" id="foobar-firstName"
>> value="" />
>>    </dd>
>>
>> Notice that the name and ID are properly formatted; this was working
>> before. now let's look at the 'email' element:
>>
>>    <dt><label for="foobar-baz-email" class="optional">Email
>> Address</label></dt>
>>    <dd>
>>        <input type="text" name="foobar[baz][email]" id="foobar-baz-email"
>> value="" />
>>    </dd>
>>
>> Notice that this is now in a *SUBARRAY*! Guess what? it works for
>> arbitrary depth -- look at the 'home' element:
>>
>>    <dt><label for="foobar-baz-bat-home" class="optional">Home
>> address?</label></dt>
>>    <dd>
>>        <input type="hidden" name="foobar[baz][bat][home]" value="0"
>>        /><input type="checkbox" name="foobar[baz][bat][home]"
>>        id="foobar-baz-bat-home" value="1"  />
>>    </dd>
>>
>> (Yes, I know there's an issue with checkboxes... ignore that for now.)
>>
>> Now, what about retrieving values? The fun part is that the returned
>> values will mimic exactly the array I pass in (except that the returned
>> values will also contain the 'save' element).
>>
>> If you're using array notation in forms, please give this a test, and
>> let me know your mileage.

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

Simon Mundy
In reply to this post by weierophinney
Hi Matthew

I'm really glad to see this added to ZF Form's capabilities. I did  
have one question, though - did you review the patch I'd sent with  
regards to getting/setting form elements as arrays? The reason I ask  
is that it makes the whole process transparent, and there's no need to  
assign sub-forms, or 'belongsto' or any of those extra methods. If  
your form name adheres to the way PHP processes form names/values then  
it populated data accordingly.

I appreciate this is a tricky bit of functionality but I think it  
could go some way to being less complex to achieve.

> I've committed some changes to Zend_Form this afternoon that make  
> using
> arrays -- including nested arrays -- seamless for setting values,
> getting values, validation, and display. However, I need to show how  
> it
> works. :-)
>
> First off, there's now a toggle, setElementsInArray(). When you set
> this on a sub form, it will automatically set the array name to the  
> sub
> form name (unless setElementsBelongTo() has already been called). This
> will allow you to quickly and easily namespace the elements in  
> subforms.
>
> Second, you can now do nested arrays, if you follow the appropriate
> steps.  The trick is that for each level of the form, you need to set
> the elementBelongsTo property to mimic what array element you're  
> using.
> So, in the sample I'll outline below, if you want to namespace the
> toplevel in 'foobar', and another subform would be in the 'baz'
> element of that array, you'd set the subform's elementsBelongTo  
> property
> to 'foobar[baz]' --- and so on, down the tree (I show an additional
> level in the example).
>
> The best part? if you don't need this feature, everything continues to
> work as it has. :-)
>
> Without further ado, here's a sample form I've been working with:
>
>    $form = new Zend_Form();
>    $form->setElementsBelongTo('foobar')
>         ->setTranslator($translate);
>
>    $form->addElement('text', 'firstName')
>         ->getElement('firstName')
>         ->setLabel('First Name')
>         ->setRequired(true);
>
>    $form->addElement('text', 'lastName')
>         ->getElement('lastName')
>         ->setLabel('Last Name')
>         ->setRequired(true);
>
>    $subForm = new Zend_Form_SubForm();
>    $subForm->setElementsBelongTo('foobar[baz]');
>    $subForm->addElement('text', 'email')
>            ->getElement('email')
>            ->setLabel('Email Address');
>
>    $subSubForm = new Zend_Form_SubForm();
>    $subSubForm->setElementsBelongTo('foobar[baz][bat]');
>    $subSubForm->addElement('checkbox', 'home')
>               ->getElement('home')
>               ->setLabel('Home address?');
>    $subForm->addSubForm($subSubForm, 'subSub');
>
>    $form->addSubForm($subForm, 'sub')
>        ->addElement('submit', 'save', array('value' => 'submit'))
>        ->setView($view);
>
>    echo $form, "\n\n";
>
>    $data = array('foobar' => array(
>        'firstName' => 'Mabel',
>        'lastName'  => 'Cow',
>        'baz'    => array(
>            'email' => '[hidden email]',
>            'bat'   => array(
>                'home' => 1,
>            )
>        )
>    ));
>
>    echo "Data validating:\n", var_export($data, 1), "\n\n";
>    echo "Result: ", var_export($form->isValid($data), 1), "\n\n";
>    echo "Retrieved values:\n", var_export($form->getValues()), "\n";
>
> Let's look at some sample output. First, the firstName element:
>
>    <dt><label for="foobar-firstName" class="required">First Name</
> label></dt>
>    <dd>
>        <input type="text" name="foobar[firstName]" id="foobar-
> firstName" value="" />
>    </dd>
>
> Notice that the name and ID are properly formatted; this was working
> before. now let's look at the 'email' element:
>
>    <dt><label for="foobar-baz-email" class="optional">Email Address</
> label></dt>
>    <dd>
>        <input type="text" name="foobar[baz][email]" id="foobar-baz-
> email" value="" />
>    </dd>
>
> Notice that this is now in a *SUBARRAY*! Guess what? it works for
> arbitrary depth -- look at the 'home' element:
>
>    <dt><label for="foobar-baz-bat-home" class="optional">Home  
> address?</label></dt>
>    <dd>
>        <input type="hidden" name="foobar[baz][bat][home]" value="0"
>        /><input type="checkbox" name="foobar[baz][bat][home]"
>        id="foobar-baz-bat-home" value="1"  />
>    </dd>
>
> (Yes, I know there's an issue with checkboxes... ignore that for now.)
>
> Now, what about retrieving values? The fun part is that the returned
> values will mimic exactly the array I pass in (except that the  
> returned
> values will also contain the 'save' element).
>
> If you're using array notation in forms, please give this a test, and
> let me know your mileage.
>
> --
> Matthew Weier O'Phinney
> PHP Developer            | [hidden email]
> Zend - The PHP Company   | http://www.zend.com/

--

Simon Mundy | Director | PEPTOLAB

""" " "" """""" "" "" """"""" " "" """"" " """"" "  """""" "" "

202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654  
4124
http://www.peptolab.com

Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

weierophinney
Administrator
-- Simon Mundy <[hidden email]> wrote
(on Saturday, 09 February 2008, 01:57 PM +1100):
> I'm really glad to see this added to ZF Form's capabilities. I did have one
> question, though - did you review the patch I'd sent with regards to
> getting/setting form elements as arrays? The reason I ask is that it makes
> the whole process transparent, and there's no need to assign sub-forms, or
> 'belongsto' or any of those extra methods. If your form name adheres to the
> way PHP processes form names/values then it populated data accordingly.
>
> I appreciate this is a tricky bit of functionality but I think it could go
> some way to being less complex to achieve.

You must not have received the email I sent you regarding the patch (I
sent one to you earlier this week). Your patch was made against the
laboratory prototype code... none of which was kept when I started
development in the incubator.

Additionally, there was another factor: the current design does not
*require* array notation for subforms; it's optional. To keep both
possible, I had to write the code the way I did. You're welcome to
review it, and if you see a way to make it more efficient while keeping
both behaviours possible (array notation and non-array notation), please
submit another patch.

> > I've committed some changes to Zend_Form this afternoon that make using
> > arrays -- including nested arrays -- seamless for setting values,
> > getting values, validation, and display. However, I need to show how it
> > works. :-)
> >
> > First off, there's now a toggle, setElementsInArray(). When you set
> > this on a sub form, it will automatically set the array name to the sub
> > form name (unless setElementsBelongTo() has already been called). This
> > will allow you to quickly and easily namespace the elements in subforms.
> >
> > Second, you can now do nested arrays, if you follow the appropriate
> > steps.  The trick is that for each level of the form, you need to set
> > the elementBelongsTo property to mimic what array element you're using.
> > So, in the sample I'll outline below, if you want to namespace the
> > toplevel in 'foobar', and another subform would be in the 'baz'
> > element of that array, you'd set the subform's elementsBelongTo property
> > to 'foobar[baz]' --- and so on, down the tree (I show an additional
> > level in the example).
> >
> > The best part? if you don't need this feature, everything continues to
> > work as it has. :-)
> >
> > Without further ado, here's a sample form I've been working with:
> >
> >    $form = new Zend_Form();
> >    $form->setElementsBelongTo('foobar')
> >         ->setTranslator($translate);
> >
> >    $form->addElement('text', 'firstName')
> >         ->getElement('firstName')
> >         ->setLabel('First Name')
> >         ->setRequired(true);
> >
> >    $form->addElement('text', 'lastName')
> >         ->getElement('lastName')
> >         ->setLabel('Last Name')
> >         ->setRequired(true);
> >
> >    $subForm = new Zend_Form_SubForm();
> >    $subForm->setElementsBelongTo('foobar[baz]');
> >    $subForm->addElement('text', 'email')
> >            ->getElement('email')
> >            ->setLabel('Email Address');
> >
> >    $subSubForm = new Zend_Form_SubForm();
> >    $subSubForm->setElementsBelongTo('foobar[baz][bat]');
> >    $subSubForm->addElement('checkbox', 'home')
> >               ->getElement('home')
> >               ->setLabel('Home address?');
> >    $subForm->addSubForm($subSubForm, 'subSub');
> >
> >    $form->addSubForm($subForm, 'sub')
> >        ->addElement('submit', 'save', array('value' => 'submit'))
> >        ->setView($view);
> >
> >    echo $form, "\n\n";
> >
> >    $data = array('foobar' => array(
> >        'firstName' => 'Mabel',
> >        'lastName'  => 'Cow',
> >        'baz'    => array(
> >            'email' => '[hidden email]',
> >            'bat'   => array(
> >                'home' => 1,
> >            )
> >        )
> >    ));
> >
> >    echo "Data validating:\n", var_export($data, 1), "\n\n";
> >    echo "Result: ", var_export($form->isValid($data), 1), "\n\n";
> >    echo "Retrieved values:\n", var_export($form->getValues()), "\n";
> >
> > Let's look at some sample output. First, the firstName element:
> >
> >    <dt><label for="foobar-firstName" class="required">First
> > Name</label></dt>
> >    <dd>
> >        <input type="text" name="foobar[firstName]" id="foobar-firstName"
> > value="" />
> >    </dd>
> >
> > Notice that the name and ID are properly formatted; this was working
> > before. now let's look at the 'email' element:
> >
> >    <dt><label for="foobar-baz-email" class="optional">Email
> > Address</label></dt>
> >    <dd>
> >        <input type="text" name="foobar[baz][email]" id="foobar-baz-email"
> > value="" />
> >    </dd>
> >
> > Notice that this is now in a *SUBARRAY*! Guess what? it works for
> > arbitrary depth -- look at the 'home' element:
> >
> >    <dt><label for="foobar-baz-bat-home" class="optional">Home
> > address?</label></dt>
> >    <dd>
> >        <input type="hidden" name="foobar[baz][bat][home]" value="0"
> >        /><input type="checkbox" name="foobar[baz][bat][home]"
> >        id="foobar-baz-bat-home" value="1"  />
> >    </dd>
> >
> > (Yes, I know there's an issue with checkboxes... ignore that for now.)
> >
> > Now, what about retrieving values? The fun part is that the returned
> > values will mimic exactly the array I pass in (except that the returned
> > values will also contain the 'save' element).
> >
> > If you're using array notation in forms, please give this a test, and
> > let me know your mileage.

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

Simon Mundy
Hi Matthew

Cool - will have a look into the process t'night. Could I clarify the  
following strategy, though?

- Currently array-notation setting/getting is only available by using  
subforms
- Parsing array-notation is only available if the setElementsInArray()  
is set

I realise the way you've done it is to allow arrays without explicitly  
setting the brackets and to build sub-groups programmatically. But is  
it the case that subforms are absolutely necessary to parse arrays?

BTW, I take it there's no support for non-associative notation (e.g.  
foo[] = 'A', foo[] = 'B')

Cheers

> -- Simon Mundy <[hidden email]> wrote
> (on Saturday, 09 February 2008, 01:57 PM +1100):
>> I'm really glad to see this added to ZF Form's capabilities. I did  
>> have one
>> question, though - did you review the patch I'd sent with regards to
>> getting/setting form elements as arrays? The reason I ask is that  
>> it makes
>> the whole process transparent, and there's no need to assign sub-
>> forms, or
>> 'belongsto' or any of those extra methods. If your form name  
>> adheres to the
>> way PHP processes form names/values then it populated data  
>> accordingly.
>>
>> I appreciate this is a tricky bit of functionality but I think it  
>> could go
>> some way to being less complex to achieve.
>
> You must not have received the email I sent you regarding the patch (I
> sent one to you earlier this week). Your patch was made against the
> laboratory prototype code... none of which was kept when I started
> development in the incubator.
>
> Additionally, there was another factor: the current design does not
> *require* array notation for subforms; it's optional. To keep both
> possible, I had to write the code the way I did. You're welcome to
> review it, and if you see a way to make it more efficient while  
> keeping
> both behaviours possible (array notation and non-array notation),  
> please
> submit another patch.
>
>>> I've committed some changes to Zend_Form this afternoon that make  
>>> using
>>> arrays -- including nested arrays -- seamless for setting values,
>>> getting values, validation, and display. However, I need to show  
>>> how it
>>> works. :-)
>>>
>>> First off, there's now a toggle, setElementsInArray(). When you set
>>> this on a sub form, it will automatically set the array name to  
>>> the sub
>>> form name (unless setElementsBelongTo() has already been called).  
>>> This
>>> will allow you to quickly and easily namespace the elements in  
>>> subforms.
>>>
>>> Second, you can now do nested arrays, if you follow the appropriate
>>> steps.  The trick is that for each level of the form, you need to  
>>> set
>>> the elementBelongsTo property to mimic what array element you're  
>>> using.
>>> So, in the sample I'll outline below, if you want to namespace the
>>> toplevel in 'foobar', and another subform would be in the 'baz'
>>> element of that array, you'd set the subform's elementsBelongTo  
>>> property
>>> to 'foobar[baz]' --- and so on, down the tree (I show an additional
>>> level in the example).
>>>
>>> The best part? if you don't need this feature, everything  
>>> continues to
>>> work as it has. :-)
>>>
>>> Without further ado, here's a sample form I've been working with:
>>>
>>>   $form = new Zend_Form();
>>>   $form->setElementsBelongTo('foobar')
>>>        ->setTranslator($translate);
>>>
>>>   $form->addElement('text', 'firstName')
>>>        ->getElement('firstName')
>>>        ->setLabel('First Name')
>>>        ->setRequired(true);
>>>
>>>   $form->addElement('text', 'lastName')
>>>        ->getElement('lastName')
>>>        ->setLabel('Last Name')
>>>        ->setRequired(true);
>>>
>>>   $subForm = new Zend_Form_SubForm();
>>>   $subForm->setElementsBelongTo('foobar[baz]');
>>>   $subForm->addElement('text', 'email')
>>>           ->getElement('email')
>>>           ->setLabel('Email Address');
>>>
>>>   $subSubForm = new Zend_Form_SubForm();
>>>   $subSubForm->setElementsBelongTo('foobar[baz][bat]');
>>>   $subSubForm->addElement('checkbox', 'home')
>>>              ->getElement('home')
>>>              ->setLabel('Home address?');
>>>   $subForm->addSubForm($subSubForm, 'subSub');
>>>
>>>   $form->addSubForm($subForm, 'sub')
>>>       ->addElement('submit', 'save', array('value' => 'submit'))
>>>       ->setView($view);
>>>
>>>   echo $form, "\n\n";
>>>
>>>   $data = array('foobar' => array(
>>>       'firstName' => 'Mabel',
>>>       'lastName'  => 'Cow',
>>>       'baz'    => array(
>>>           'email' => '[hidden email]',
>>>           'bat'   => array(
>>>               'home' => 1,
>>>           )
>>>       )
>>>   ));
>>>
>>>   echo "Data validating:\n", var_export($data, 1), "\n\n";
>>>   echo "Result: ", var_export($form->isValid($data), 1), "\n\n";
>>>   echo "Retrieved values:\n", var_export($form->getValues()), "\n";
>>>
>>> Let's look at some sample output. First, the firstName element:
>>>
>>>   <dt><label for="foobar-firstName" class="required">First
>>> Name</label></dt>
>>>   <dd>
>>>       <input type="text" name="foobar[firstName]" id="foobar-
>>> firstName"
>>> value="" />
>>>   </dd>
>>>
>>> Notice that the name and ID are properly formatted; this was working
>>> before. now let's look at the 'email' element:
>>>
>>>   <dt><label for="foobar-baz-email" class="optional">Email
>>> Address</label></dt>
>>>   <dd>
>>>       <input type="text" name="foobar[baz][email]" id="foobar-baz-
>>> email"
>>> value="" />
>>>   </dd>
>>>
>>> Notice that this is now in a *SUBARRAY*! Guess what? it works for
>>> arbitrary depth -- look at the 'home' element:
>>>
>>>   <dt><label for="foobar-baz-bat-home" class="optional">Home
>>> address?</label></dt>
>>>   <dd>
>>>       <input type="hidden" name="foobar[baz][bat][home]" value="0"
>>>       /><input type="checkbox" name="foobar[baz][bat][home]"
>>>       id="foobar-baz-bat-home" value="1"  />
>>>   </dd>
>>>
>>> (Yes, I know there's an issue with checkboxes... ignore that for  
>>> now.)
>>>
>>> Now, what about retrieving values? The fun part is that the returned
>>> values will mimic exactly the array I pass in (except that the  
>>> returned
>>> values will also contain the 'save' element).
>>>
>>> If you're using array notation in forms, please give this a test,  
>>> and
>>> let me know your mileage.
>
> --
> Matthew Weier O'Phinney
> PHP Developer            | [hidden email]
> Zend - The PHP Company   | http://www.zend.com/

--

Simon Mundy | Director | PEPTOLAB

""" " "" """""" "" "" """"""" " "" """"" " """"" "  """""" "" "

202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654  
4124
http://www.peptolab.com

Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

weierophinney
Administrator
-- Simon Mundy <[hidden email]> wrote
(on Saturday, 09 February 2008, 02:23 PM +1100):
> Cool - will have a look into the process t'night. Could I clarify the
> following strategy, though?
>
> - Currently array-notation setting/getting is only available by using
> subforms

No -- it can be done at the form level and element level as well. You
can tell an element that it belongs to an array:

    $element->setBelongsTo('foo[bar]');

though that only affects display, not validation.

And you can tell a *form* (not just a sub form) that it *is* an array:

    $element->setElementsBelongTo('foo');

and that affects all arenas.

> - Parsing array-notation is only available if the setElementsInArray() is
> set

That and/or setElementsBelongTo(), yes.

> I realise the way you've done it is to allow arrays without explicitly
> setting the brackets and to build sub-groups programmatically. But is it
> the case that subforms are absolutely necessary to parse arrays?

No -- note that it can be set at the form level as well.

> BTW, I take it there's no support for non-associative notation (e.g. foo[]
> = 'A', foo[] = 'B')

That would simply mean that the value coming into the element is an
array, and it would be up to the element validators and filters to
handle it.


>> -- Simon Mundy <[hidden email]> wrote
>> (on Saturday, 09 February 2008, 01:57 PM +1100):
>>> I'm really glad to see this added to ZF Form's capabilities. I did have
>>> one
>>> question, though - did you review the patch I'd sent with regards to
>>> getting/setting form elements as arrays? The reason I ask is that it
>>> makes
>>> the whole process transparent, and there's no need to assign sub-forms,
>>> or
>>> 'belongsto' or any of those extra methods. If your form name adheres to
>>> the
>>> way PHP processes form names/values then it populated data accordingly.
>>>
>>> I appreciate this is a tricky bit of functionality but I think it could
>>> go
>>> some way to being less complex to achieve.
>>
>> You must not have received the email I sent you regarding the patch (I
>> sent one to you earlier this week). Your patch was made against the
>> laboratory prototype code... none of which was kept when I started
>> development in the incubator.
>>
>> Additionally, there was another factor: the current design does not
>> *require* array notation for subforms; it's optional. To keep both
>> possible, I had to write the code the way I did. You're welcome to
>> review it, and if you see a way to make it more efficient while keeping
>> both behaviours possible (array notation and non-array notation), please
>> submit another patch.
>>
>>>> I've committed some changes to Zend_Form this afternoon that make using
>>>> arrays -- including nested arrays -- seamless for setting values,
>>>> getting values, validation, and display. However, I need to show how it
>>>> works. :-)
>>>>
>>>> First off, there's now a toggle, setElementsInArray(). When you set
>>>> this on a sub form, it will automatically set the array name to the sub
>>>> form name (unless setElementsBelongTo() has already been called). This
>>>> will allow you to quickly and easily namespace the elements in subforms.
>>>>
>>>> Second, you can now do nested arrays, if you follow the appropriate
>>>> steps.  The trick is that for each level of the form, you need to set
>>>> the elementBelongsTo property to mimic what array element you're using.
>>>> So, in the sample I'll outline below, if you want to namespace the
>>>> toplevel in 'foobar', and another subform would be in the 'baz'
>>>> element of that array, you'd set the subform's elementsBelongTo property
>>>> to 'foobar[baz]' --- and so on, down the tree (I show an additional
>>>> level in the example).
>>>>
>>>> The best part? if you don't need this feature, everything continues to
>>>> work as it has. :-)
>>>>
>>>> Without further ado, here's a sample form I've been working with:
>>>>
>>>>   $form = new Zend_Form();
>>>>   $form->setElementsBelongTo('foobar')
>>>>        ->setTranslator($translate);
>>>>
>>>>   $form->addElement('text', 'firstName')
>>>>        ->getElement('firstName')
>>>>        ->setLabel('First Name')
>>>>        ->setRequired(true);
>>>>
>>>>   $form->addElement('text', 'lastName')
>>>>        ->getElement('lastName')
>>>>        ->setLabel('Last Name')
>>>>        ->setRequired(true);
>>>>
>>>>   $subForm = new Zend_Form_SubForm();
>>>>   $subForm->setElementsBelongTo('foobar[baz]');
>>>>   $subForm->addElement('text', 'email')
>>>>           ->getElement('email')
>>>>           ->setLabel('Email Address');
>>>>
>>>>   $subSubForm = new Zend_Form_SubForm();
>>>>   $subSubForm->setElementsBelongTo('foobar[baz][bat]');
>>>>   $subSubForm->addElement('checkbox', 'home')
>>>>              ->getElement('home')
>>>>              ->setLabel('Home address?');
>>>>   $subForm->addSubForm($subSubForm, 'subSub');
>>>>
>>>>   $form->addSubForm($subForm, 'sub')
>>>>       ->addElement('submit', 'save', array('value' => 'submit'))
>>>>       ->setView($view);
>>>>
>>>>   echo $form, "\n\n";
>>>>
>>>>   $data = array('foobar' => array(
>>>>       'firstName' => 'Mabel',
>>>>       'lastName'  => 'Cow',
>>>>       'baz'    => array(
>>>>           'email' => '[hidden email]',
>>>>           'bat'   => array(
>>>>               'home' => 1,
>>>>           )
>>>>       )
>>>>   ));
>>>>
>>>>   echo "Data validating:\n", var_export($data, 1), "\n\n";
>>>>   echo "Result: ", var_export($form->isValid($data), 1), "\n\n";
>>>>   echo "Retrieved values:\n", var_export($form->getValues()), "\n";
>>>>
>>>> Let's look at some sample output. First, the firstName element:
>>>>
>>>>   <dt><label for="foobar-firstName" class="required">First
>>>> Name</label></dt>
>>>>   <dd>
>>>>       <input type="text" name="foobar[firstName]" id="foobar-firstName"
>>>> value="" />
>>>>   </dd>
>>>>
>>>> Notice that the name and ID are properly formatted; this was working
>>>> before. now let's look at the 'email' element:
>>>>
>>>>   <dt><label for="foobar-baz-email" class="optional">Email
>>>> Address</label></dt>
>>>>   <dd>
>>>>       <input type="text" name="foobar[baz][email]" id="foobar-baz-email"
>>>> value="" />
>>>>   </dd>
>>>>
>>>> Notice that this is now in a *SUBARRAY*! Guess what? it works for
>>>> arbitrary depth -- look at the 'home' element:
>>>>
>>>>   <dt><label for="foobar-baz-bat-home" class="optional">Home
>>>> address?</label></dt>
>>>>   <dd>
>>>>       <input type="hidden" name="foobar[baz][bat][home]" value="0"
>>>>       /><input type="checkbox" name="foobar[baz][bat][home]"
>>>>       id="foobar-baz-bat-home" value="1"  />
>>>>   </dd>
>>>>
>>>> (Yes, I know there's an issue with checkboxes... ignore that for now.)
>>>>
>>>> Now, what about retrieving values? The fun part is that the returned
>>>> values will mimic exactly the array I pass in (except that the returned
>>>> values will also contain the 'save' element).
>>>>
>>>> If you're using array notation in forms, please give this a test, and
>>>> let me know your mileage.
>>
>> --
>> Matthew Weier O'Phinney
>> PHP Developer            | [hidden email]
>> Zend - The PHP Company   | http://www.zend.com/
>
> --
>
> Simon Mundy | Director | PEPTOLAB
>
> """ " "" """""" "" "" """"""" " "" """"" " """"" "  """""" "" "
>
> 202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
> Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654 4124
> http://www.peptolab.com
>

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

Amr Mostafa
In reply to this post by weierophinney
Hi Matthew,

Thanks so much for improving this area, and I feel there are still room for improvement

It seems like indeed as Simon noted, it could be more transparent. For example, in the nested forms example, why and how subforms have to set their own belongsTo. It doesn't seem correct as they shouldn't assume that piece of information. i.e. in your example: $subSubForm->setElementsBelongTo('foobar[baz][bat]');
'foobar[baz]' is about 2 parent Form which $subSubForm doesn't have access to.

Normally, I'd imagine the parents assigning these belongsTo on childs.

Best,
- Amr

On Feb 8, 2008 11:56 PM, Matthew Weier O'Phinney <[hidden email]> wrote:
I've committed some changes to Zend_Form this afternoon that make using
arrays -- including nested arrays -- seamless for setting values,
getting values, validation, and display. However, I need to show how it
works. :-)

First off, there's now a toggle, setElementsInArray(). When you set
this on a sub form, it will automatically set the array name to the sub
form name (unless setElementsBelongTo() has already been called). This
will allow you to quickly and easily namespace the elements in subforms.

Second, you can now do nested arrays, if you follow the appropriate
steps.  The trick is that for each level of the form, you need to set
the elementBelongsTo property to mimic what array element you're using.
So, in the sample I'll outline below, if you want to namespace the
toplevel in 'foobar', and another subform would be in the 'baz'
element of that array, you'd set the subform's elementsBelongTo property
to 'foobar[baz]' --- and so on, down the tree (I show an additional
level in the example).

The best part? if you don't need this feature, everything continues to
work as it has. :-)

Without further ado, here's a sample form I've been working with:

   $form = new Zend_Form();
   $form->setElementsBelongTo('foobar')
        ->setTranslator($translate);

   $form->addElement('text', 'firstName')
        ->getElement('firstName')
        ->setLabel('First Name')
        ->setRequired(true);

   $form->addElement('text', 'lastName')
        ->getElement('lastName')
        ->setLabel('Last Name')
        ->setRequired(true);

   $subForm = new Zend_Form_SubForm();
   $subForm->setElementsBelongTo('foobar[baz]');
   $subForm->addElement('text', 'email')
           ->getElement('email')
           ->setLabel('Email Address');

   $subSubForm = new Zend_Form_SubForm();
   $subSubForm->setElementsBelongTo('foobar[baz][bat]');
   $subSubForm->addElement('checkbox', 'home')
              ->getElement('home')
              ->setLabel('Home address?');
   $subForm->addSubForm($subSubForm, 'subSub');

   $form->addSubForm($subForm, 'sub')
       ->addElement('submit', 'save', array('value' => 'submit'))
       ->setView($view);

   echo $form, "\n\n";

   $data = array('foobar' => array(
       'firstName' => 'Mabel',
       'lastName'  => 'Cow',
       'baz'    => array(
           'email' => '[hidden email]',
           'bat'   => array(
               'home' => 1,
           )
       )
   ));

   echo "Data validating:\n", var_export($data, 1), "\n\n";
   echo "Result: ", var_export($form->isValid($data), 1), "\n\n";
   echo "Retrieved values:\n", var_export($form->getValues()), "\n";

Let's look at some sample output. First, the firstName element:

   <dt><label for="foobar-firstName" class="required">First Name</label></dt>
   <dd>
       <input type="text" name="foobar[firstName]" id="foobar-firstName" value="" />
   </dd>

Notice that the name and ID are properly formatted; this was working
before. now let's look at the 'email' element:

   <dt><label for="foobar-baz-email" class="optional">Email Address</label></dt>
   <dd>
       <input type="text" name="foobar[baz][email]" id="foobar-baz-email" value="" />
   </dd>

Notice that this is now in a *SUBARRAY*! Guess what? it works for
arbitrary depth -- look at the 'home' element:

   <dt><label for="foobar-baz-bat-home" class="optional">Home address?</label></dt>
   <dd>
       <input type="hidden" name="foobar[baz][bat][home]" value="0"
       /><input type="checkbox" name="foobar[baz][bat][home]"
       id="foobar-baz-bat-home" value="1"  />
   </dd>

(Yes, I know there's an issue with checkboxes... ignore that for now.)

Now, what about retrieving values? The fun part is that the returned
values will mimic exactly the array I pass in (except that the returned
values will also contain the 'save' element).

If you're using array notation in forms, please give this a test, and
let me know your mileage.

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/

Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

Amr Mostafa
Code talks better, I've tried to implement what I suggested, parents should set the belongsTo for childs, and surprisingly it worked. It took a render() override:

    /**
     * Render form
     *
     * @param  Zend_View_Interface $view
     * @return string
     */
    public function render(Zend_View_Interface $view = null)
    {
        if ($this->getElementsInArray()) {
            foreach ($this->getSubForms() as $subForm) {
                $subForm->setElementsBelongTo($this->getElementsBelongTo() . '[' . $subForm->getName() . ']');
            }
        }

        return parent::render($view);
    }
}

So in your example earlier we could have setElementsBelongTo() on subForm and subSubForm removed.

Cheers,
- Amr

On Feb 9, 2008 6:48 PM, Amr Mostafa <[hidden email]> wrote:
Hi Matthew,

Thanks so much for improving this area, and I feel there are still room for improvement

It seems like indeed as Simon noted, it could be more transparent. For example, in the nested forms example, why and how subforms have to set their own belongsTo. It doesn't seem correct as they shouldn't assume that piece of information. i.e. in your example: $subSubForm->setElementsBelongTo('foobar[baz][bat]');
'foobar[baz]' is about 2 parent Form which $subSubForm doesn't have access to.

Normally, I'd imagine the parents assigning these belongsTo on childs.

Best,
- Amr


On Feb 8, 2008 11:56 PM, Matthew Weier O'Phinney <[hidden email]> wrote:
I've committed some changes to Zend_Form this afternoon that make using
arrays -- including nested arrays -- seamless for setting values,
getting values, validation, and display. However, I need to show how it
works. :-)

First off, there's now a toggle, setElementsInArray(). When you set
this on a sub form, it will automatically set the array name to the sub
form name (unless setElementsBelongTo() has already been called). This
will allow you to quickly and easily namespace the elements in subforms.

Second, you can now do nested arrays, if you follow the appropriate
steps.  The trick is that for each level of the form, you need to set
the elementBelongsTo property to mimic what array element you're using.
So, in the sample I'll outline below, if you want to namespace the
toplevel in 'foobar', and another subform would be in the 'baz'
element of that array, you'd set the subform's elementsBelongTo property
to 'foobar[baz]' --- and so on, down the tree (I show an additional
level in the example).

The best part? if you don't need this feature, everything continues to
work as it has. :-)

Without further ado, here's a sample form I've been working with:

   $form = new Zend_Form();
   $form->setElementsBelongTo('foobar')
        ->setTranslator($translate);

   $form->addElement('text', 'firstName')
        ->getElement('firstName')
        ->setLabel('First Name')
        ->setRequired(true);

   $form->addElement('text', 'lastName')
        ->getElement('lastName')
        ->setLabel('Last Name')
        ->setRequired(true);

   $subForm = new Zend_Form_SubForm();
   $subForm->setElementsBelongTo('foobar[baz]');
   $subForm->addElement('text', 'email')
           ->getElement('email')
           ->setLabel('Email Address');

   $subSubForm = new Zend_Form_SubForm();
   $subSubForm->setElementsBelongTo('foobar[baz][bat]');
   $subSubForm->addElement('checkbox', 'home')
              ->getElement('home')
              ->setLabel('Home address?');
   $subForm->addSubForm($subSubForm, 'subSub');

   $form->addSubForm($subForm, 'sub')
       ->addElement('submit', 'save', array('value' => 'submit'))
       ->setView($view);

   echo $form, "\n\n";

   $data = array('foobar' => array(
       'firstName' => 'Mabel',
       'lastName'  => 'Cow',
       'baz'    => array(
           'email' => '[hidden email]',
           'bat'   => array(
               'home' => 1,
           )
       )
   ));

   echo "Data validating:\n", var_export($data, 1), "\n\n";
   echo "Result: ", var_export($form->isValid($data), 1), "\n\n";
   echo "Retrieved values:\n", var_export($form->getValues()), "\n";

Let's look at some sample output. First, the firstName element:

   <dt><label for="foobar-firstName" class="required">First Name</label></dt>
   <dd>
       <input type="text" name="foobar[firstName]" id="foobar-firstName" value="" />
   </dd>

Notice that the name and ID are properly formatted; this was working
before. now let's look at the 'email' element:

   <dt><label for="foobar-baz-email" class="optional">Email Address</label></dt>
   <dd>
       <input type="text" name="foobar[baz][email]" id="foobar-baz-email" value="" />
   </dd>

Notice that this is now in a *SUBARRAY*! Guess what? it works for
arbitrary depth -- look at the 'home' element:

   <dt><label for="foobar-baz-bat-home" class="optional">Home address?</label></dt>
   <dd>
       <input type="hidden" name="foobar[baz][bat][home]" value="0"
       /><input type="checkbox" name="foobar[baz][bat][home]"
       id="foobar-baz-bat-home" value="1"  />
   </dd>

(Yes, I know there's an issue with checkboxes... ignore that for now.)

Now, what about retrieving values? The fun part is that the returned
values will mimic exactly the array I pass in (except that the returned
values will also contain the 'save' element).

If you're using array notation in forms, please give this a test, and
let me know your mileage.

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/


Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

Eric Coleman-3
In reply to this post by weierophinney
Matthew,

Are you aware that if you put a few elements into a DisplayGroup, you  
loose the array support?

Regards,
Eric
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

weierophinney
Administrator
-- Eric Coleman <[hidden email]> wrote
(on Sunday, 10 February 2008, 10:55 AM -0500):
> Are you aware that if you put a few elements into a DisplayGroup, you loose
> the array support?

Not sure I understand you. Can you give me some code showing how to
reproduce, including expected and actual results?

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

André Vignaud
In reply to this post by weierophinney
Thanks Matthew for your answer.
However I was looking for something like the init process done by the isValid() function.
What's about having this done as a separate function ?

Regards,

André

Matthew Weier O'Phinney a écrit :
> -- André VIGNAUD <avignaud@kapiasolutions.com> wrote
> (on Sunday, 10 February 2008, 04:47 PM +0100):
>> Thanks for you great job on Zend_Form and to this new improved array
>> support.
>> When trying your example, I did not found how to easily set the form
>> default values using $data ?
>> Trying $form->setDefaults($data) does'not work as I wish ? Any idea ?
>
> Simply do them as key/value pairs under the 'defaults' key:
>
>     form.defaults.<elementName> = <value>
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

weierophinney
Administrator
-- André VIGNAUD <[hidden email]> wrote
(on Sunday, 10 February 2008, 12:03 PM -0800):
> Thanks Matthew for your answer.
> However I was looking for something like the init process done by the
> isValid() function.
> What's about having this done as a separate function ?

I'm not sure what you're getting at. You simply asked how to set the
form default values, and I gave a way to do so. Looking at my answer,
and, seeing my response, I was a little remiss -- if you want to set
default values, simply specify $form->setDefaults($data), where $data is
a set of key/value pairs.

It sounds, however, like you are desiring some other functionality.
Please specify clearly what you want to happen: how you would call it,
and the desired result.

> Matthew Weier O'Phinney a écrit :
> > -- André VIGNAUD <[hidden email]> wrote
> > (on Sunday, 10 February 2008, 04:47 PM +0100):
> > > Thanks for you great job on Zend_Form and to this new improved array
> > > support.
> > > When trying your example, I did not found how to easily set the form
> > > default values using $data ?
> > > Trying $form->setDefaults($data) does'not work as I wish ? Any idea ?
> >
> > Simply do them as key/value pairs under the 'defaults' key:
> >
> >     form.defaults.<elementName> = <value>

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

André Vignaud
Sorry I will try to explain my need.

Suppose I want to build a form for editing a person name, address and optionally email.
First I need to display the form with current person's data. So when my action is called without post data I get person's data (from the database) as an array and want to put directly this data into the form so it will display the person's informations.
Second I have a submit button allowing to add an email. When user choose this option, the form is posted and I just add the new email element to the form. After that I need to redisplay my form with the same data user has entered.

Here is a sample code :

        $form = new Zend_Form();
        $form->setElementsBelongTo('person');

        $form->addElement('text', 'firstName')
             ->getElement('firstName')
             ->setLabel('First Name')
             ->setRequired(true);
               
        $form->addElement('text', 'lastName')
             ->getElement('lastName')
             ->setLabel('Last Name')
             ->setRequired(true);
               
        $subForm = new Zend_Form_SubForm();
        $subForm->setElementsBelongTo('foobar[address]');
        $subForm->addElement('text', 'street')
                ->getElement('street')
                ->setLabel('Address');

        $subForm->addElement('text', 'city')
                ->getElement('city')
                ->setLabel('City');

        $form->addSubForm($subForm, 'sub')
            // here is the option for adding an email element
            ->addElement('submit', 'addcontact', array('value' => 'add contact'))
            ->addElement('submit', 'save', array('value' => 'submit'))
            ->setView($view);
               
        if ( $request->isPost()) {
            // check if save submit button selected
            if ( isset($_POST['person']['save']) ) {
                if ( $form->isValid($_POST) ) {
                    $validData = $form->getValues();
                    // do some stuf with validData
                }
            }
            // check if addcontact button selected
            elseif ( isset($_POST['person']['addcontact'])) {
                $subForm = new Zend_Form_SubForm();
                $subForm->setElementsBelongTo('foobar[contact]');
                $subForm->addElement('text', 'email')
                        ->getElement('email')
                        ->setLabel('Contact Email');
                $form->addSubForm($subForm, 'sub2');
                // need to fill the form with $_POSTdata ?
            }
        }
        else {
            // retrieve data to initialize the form
            $data = array(
                'person' => array(
                    'firstName' => 'Jean',
                    'lastName'  => 'Dupont',
                    'address'    => array(
                        'street' => 'rue de la pointe',
                        'city'   => 'Paris',
                    )
                )
            );
            // need to fill the form with init data
        }

What is the best way to do that ?

Thanks for your help and explaination.

Best regards,

André

Matthew Weier O'Phinney-3 wrote
-- André VIGNAUD <avignaud@kapiasolutions.com> wrote
(on Sunday, 10 February 2008, 12:03 PM -0800):
> Thanks Matthew for your answer.
> However I was looking for something like the init process done by the
> isValid() function.
> What's about having this done as a separate function ?

I'm not sure what you're getting at. You simply asked how to set the
form default values, and I gave a way to do so. Looking at my answer,
and, seeing my response, I was a little remiss -- if you want to set
default values, simply specify $form->setDefaults($data), where $data is
a set of key/value pairs.

It sounds, however, like you are desiring some other functionality.
Please specify clearly what you want to happen: how you would call it,
and the desired result.

> Matthew Weier O'Phinney a écrit :
> > -- André VIGNAUD <avignaud@kapiasolutions.com> wrote
> > (on Sunday, 10 February 2008, 04:47 PM +0100):
> > > Thanks for you great job on Zend_Form and to this new improved array
> > > support.
> > > When trying your example, I did not found how to easily set the form
> > > default values using $data ?
> > > Trying $form->setDefaults($data) does'not work as I wish ? Any idea ?
> >
> > Simply do them as key/value pairs under the 'defaults' key:
> >
> >     form.defaults.<elementName> = <value>

--
Matthew Weier O'Phinney
PHP Developer            | matthew@zend.com
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

weierophinney
Administrator
-- André Vignaud <[hidden email]> wrote
(on Sunday, 10 February 2008, 03:29 PM -0800):
> Sorry I will try to explain my need.
>
> Suppose I want to build a form for editing a person name, address and
> optionally email.
> First I need to display the form with current person's data. So when my
> action is called without post data I get person's data (from the database)
> as an array and want to put directly this data into the form so it will
> display the person's informations.

So, take that data and call either:

    $form-> setDefaults($data);
    // or
    $form-> populate($data);

prior to displaying the form. This will set the values, which will be
used when rendering the form. Just make sure that the data you pass is
an array; if it is not, figure out a way to cast it to an array.
Zend_Db_Table_Row objects can be cast to arrays using $row-> toArray(),
as can many other classes in ZF.

> Second I have a submit button allowing to add an email. When user choose
> this option, the form is posted and I just add the new email element to the
> form. After that I need to redisplay my form with the same data user has
> entered.

After calling isValid(), the form values are populated from the data
validated, and when you display the form, they will be displayed.

If you want to make sure only updated values are updated in the
database, I'd recommend storing the original values you used to populate
the form in your session, and then check those values against your
submitted data.

Is there some part of this process that *isn't* working for you?

> Here is a sample code :
>
>         $form = new Zend_Form();
>         $form-> setElementsBelongTo('person');
>
>         $form-> addElement('text', 'firstName')
>              -> getElement('firstName')
>              -> setLabel('First Name')
>              -> setRequired(true);
>                
>         $form-> addElement('text', 'lastName')
>              -> getElement('lastName')
>              -> setLabel('Last Name')
>              -> setRequired(true);
>                
>         $subForm = new Zend_Form_SubForm();
>         $subForm-> setElementsBelongTo('foobar[address]');
>         $subForm-> addElement('text', 'street')
>                 -> getElement('street')
>                 -> setLabel('Address');
>
>         $subForm-> addElement('text', 'city')
>                 -> getElement('city')
>                 -> setLabel('City');
>
>         $form-> addSubForm($subForm, 'sub')
>             // here is the option for adding an email element
>             -> addElement('submit', 'addcontact', array('value' => 'add
> contact'))
>             -> addElement('submit', 'save', array('value' => 'submit'))
>             -> setView($view);
>                
>         if ( $request-> isPost()) {
>             // check if save submit button selected
>             if ( isset($_POST['person']['save']) ) {
>                 if ( $form-> isValid($_POST) ) {
>                     $validData = $form-> getValues();
>                     // do some stuf with validData
>                 }
>             }
>             // check if addcontact button selected
>             elseif ( isset($_POST['person']['addcontact'])) {
>                 $subForm = new Zend_Form_SubForm();
>                 $subForm-> setElementsBelongTo('foobar[contact]');
>                 $subForm-> addElement('text', 'email')
>                         -> getElement('email')
>                         -> setLabel('Contact Email');
>                 $form-> addSubForm($subForm, 'sub2');
>                 // need to fill the form with $_POSTdata ?
>             }
>         }
>         else {
>             // retrieve data to initialize the form
>             $data = array(
>                 'person' => array(
>                     'firstName' => 'Jean',
>                     'lastName'  => 'Dupont',
>                     'address'    => array(
>                         'street' => 'rue de la pointe',
>                         'city'   => 'Paris',
>                     )
>                 )
>             );
>             // need to fill the form with init data
>         }
>
> What is the best way to do that ?
>
> Thanks for your help and explaination.
>
> Best regards,
>
> André
>
>
> Matthew Weier O'Phinney-3 wrote:
> >
> > -- André VIGNAUD <[hidden email]> wrote
> > (on Sunday, 10 February 2008, 12:03 PM -0800):
> > > Thanks Matthew for your answer.
> > > However I was looking for something like the init process done by the
> > > isValid() function.
> > > What's about having this done as a separate function ?
> >
> > I'm not sure what you're getting at. You simply asked how to set the
> > form default values, and I gave a way to do so. Looking at my answer,
> > and, seeing my response, I was a little remiss -- if you want to set
> > default values, simply specify $form-> setDefaults($data), where $data is
> > a set of key/value pairs.
> >
> > It sounds, however, like you are desiring some other functionality.
> > Please specify clearly what you want to happen: how you would call it,
> > and the desired result.
> >
> > > Matthew Weier O'Phinney a écrit :
> > > > -- André VIGNAUD <[hidden email]> wrote
> > > > (on Sunday, 10 February 2008, 04:47 PM +0100):
> > > > > Thanks for you great job on Zend_Form and to this new improved array
> > > > > support.
> > > > > When trying your example, I did not found how to easily set the form
> > > > > default values using $data ?
> > > > > Trying $form-> setDefaults($data) does'not work as I wish ? Any idea ?
> > > >
> > > > Simply do them as key/value pairs under the 'defaults' key:
> > > >
> > > >     form.defaults.<elementName> = <value>

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

André Vignaud
I will try this, thanks again for your help

Matthew Weier O'Phinney-3 wrote
-- André Vignaud <avignaud@kapiasolutions.com> wrote
(on Sunday, 10 February 2008, 03:29 PM -0800):
> Sorry I will try to explain my need.
>
> Suppose I want to build a form for editing a person name, address and
> optionally email.
> First I need to display the form with current person's data. So when my
> action is called without post data I get person's data (from the database)
> as an array and want to put directly this data into the form so it will
> display the person's informations.

So, take that data and call either:

    $form-> setDefaults($data);
    // or
    $form-> populate($data);

prior to displaying the form. This will set the values, which will be
used when rendering the form. Just make sure that the data you pass is
an array; if it is not, figure out a way to cast it to an array.
Zend_Db_Table_Row objects can be cast to arrays using $row-> toArray(),
as can many other classes in ZF.

> Second I have a submit button allowing to add an email. When user choose
> this option, the form is posted and I just add the new email element to the
> form. After that I need to redisplay my form with the same data user has
> entered.

After calling isValid(), the form values are populated from the data
validated, and when you display the form, they will be displayed.

If you want to make sure only updated values are updated in the
database, I'd recommend storing the original values you used to populate
the form in your session, and then check those values against your
submitted data.

Is there some part of this process that *isn't* working for you?

> Here is a sample code :
>
>         $form = new Zend_Form();
>         $form-> setElementsBelongTo('person');
>
>         $form-> addElement('text', 'firstName')
>              -> getElement('firstName')
>              -> setLabel('First Name')
>              -> setRequired(true);
>                
>         $form-> addElement('text', 'lastName')
>              -> getElement('lastName')
>              -> setLabel('Last Name')
>              -> setRequired(true);
>                
>         $subForm = new Zend_Form_SubForm();
>         $subForm-> setElementsBelongTo('foobar[address]');
>         $subForm-> addElement('text', 'street')
>                 -> getElement('street')
>                 -> setLabel('Address');
>
>         $subForm-> addElement('text', 'city')
>                 -> getElement('city')
>                 -> setLabel('City');
>
>         $form-> addSubForm($subForm, 'sub')
>             // here is the option for adding an email element
>             -> addElement('submit', 'addcontact', array('value' => 'add
> contact'))
>             -> addElement('submit', 'save', array('value' => 'submit'))
>             -> setView($view);
>                
>         if ( $request-> isPost()) {
>             // check if save submit button selected
>             if ( isset($_POST['person']['save']) ) {
>                 if ( $form-> isValid($_POST) ) {
>                     $validData = $form-> getValues();
>                     // do some stuf with validData
>                 }
>             }
>             // check if addcontact button selected
>             elseif ( isset($_POST['person']['addcontact'])) {
>                 $subForm = new Zend_Form_SubForm();
>                 $subForm-> setElementsBelongTo('foobar[contact]');
>                 $subForm-> addElement('text', 'email')
>                         -> getElement('email')
>                         -> setLabel('Contact Email');
>                 $form-> addSubForm($subForm, 'sub2');
>                 // need to fill the form with $_POSTdata ?
>             }
>         }
>         else {
>             // retrieve data to initialize the form
>             $data = array(
>                 'person' => array(
>                     'firstName' => 'Jean',
>                     'lastName'  => 'Dupont',
>                     'address'    => array(
>                         'street' => 'rue de la pointe',
>                         'city'   => 'Paris',
>                     )
>                 )
>             );
>             // need to fill the form with init data
>         }
>
> What is the best way to do that ?
>
> Thanks for your help and explaination.
>
> Best regards,
>
> André
>
>
> Matthew Weier O'Phinney-3 wrote:
> >
> > -- André VIGNAUD <avignaud@kapiasolutions.com> wrote
> > (on Sunday, 10 February 2008, 12:03 PM -0800):
> > > Thanks Matthew for your answer.
> > > However I was looking for something like the init process done by the
> > > isValid() function.
> > > What's about having this done as a separate function ?
> >
> > I'm not sure what you're getting at. You simply asked how to set the
> > form default values, and I gave a way to do so. Looking at my answer,
> > and, seeing my response, I was a little remiss -- if you want to set
> > default values, simply specify $form-> setDefaults($data), where $data is
> > a set of key/value pairs.
> >
> > It sounds, however, like you are desiring some other functionality.
> > Please specify clearly what you want to happen: how you would call it,
> > and the desired result.
> >
> > > Matthew Weier O'Phinney a écrit :
> > > > -- André VIGNAUD <avignaud@kapiasolutions.com> wrote
> > > > (on Sunday, 10 February 2008, 04:47 PM +0100):
> > > > > Thanks for you great job on Zend_Form and to this new improved array
> > > > > support.
> > > > > When trying your example, I did not found how to easily set the form
> > > > > default values using $data ?
> > > > > Trying $form-> setDefaults($data) does'not work as I wish ? Any idea ?
> > > >
> > > > Simply do them as key/value pairs under the 'defaults' key:
> > > >
> > > >     form.defaults.<elementName> = <value>

--
Matthew Weier O'Phinney
PHP Developer            | matthew@zend.com
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

weierophinney
Administrator
In reply to this post by Simon Mundy
Simon and anyone else interested:

I've changed the array support in current trunk. Please check out my
reply to Eric Coleman on a later thread:

    http://www.nabble.com/Re%3A-Zend_Form%3A-Element-Array-Oddness-p15510809s16154.html

I think this will answer the issues you and others have raised. :-)

-- Simon Mundy <[hidden email]> wrote
(on Saturday, 09 February 2008, 02:23 PM +1100):

> Hi Matthew
>
> Cool - will have a look into the process t'night. Could I clarify the
> following strategy, though?
>
> - Currently array-notation setting/getting is only available by using
> subforms
> - Parsing array-notation is only available if the setElementsInArray() is
> set
>
> I realise the way you've done it is to allow arrays without explicitly
> setting the brackets and to build sub-groups programmatically. But is it
> the case that subforms are absolutely necessary to parse arrays?
>
> BTW, I take it there's no support for non-associative notation (e.g. foo[]
> = 'A', foo[] = 'B')
>
> Cheers
>
>> -- Simon Mundy <[hidden email]> wrote
>> (on Saturday, 09 February 2008, 01:57 PM +1100):
>>> I'm really glad to see this added to ZF Form's capabilities. I did have
>>> one
>>> question, though - did you review the patch I'd sent with regards to
>>> getting/setting form elements as arrays? The reason I ask is that it
>>> makes
>>> the whole process transparent, and there's no need to assign sub-forms,
>>> or
>>> 'belongsto' or any of those extra methods. If your form name adheres to
>>> the
>>> way PHP processes form names/values then it populated data accordingly.
>>>
>>> I appreciate this is a tricky bit of functionality but I think it could
>>> go
>>> some way to being less complex to achieve.
>>
>> You must not have received the email I sent you regarding the patch (I
>> sent one to you earlier this week). Your patch was made against the
>> laboratory prototype code... none of which was kept when I started
>> development in the incubator.
>>
>> Additionally, there was another factor: the current design does not
>> *require* array notation for subforms; it's optional. To keep both
>> possible, I had to write the code the way I did. You're welcome to
>> review it, and if you see a way to make it more efficient while keeping
>> both behaviours possible (array notation and non-array notation), please
>> submit another patch.
>>
>>>> I've committed some changes to Zend_Form this afternoon that make using
>>>> arrays -- including nested arrays -- seamless for setting values,
>>>> getting values, validation, and display. However, I need to show how it
>>>> works. :-)
>>>>
>>>> First off, there's now a toggle, setElementsInArray(). When you set
>>>> this on a sub form, it will automatically set the array name to the sub
>>>> form name (unless setElementsBelongTo() has already been called). This
>>>> will allow you to quickly and easily namespace the elements in subforms.
>>>>
>>>> Second, you can now do nested arrays, if you follow the appropriate
>>>> steps.  The trick is that for each level of the form, you need to set
>>>> the elementBelongsTo property to mimic what array element you're using.
>>>> So, in the sample I'll outline below, if you want to namespace the
>>>> toplevel in 'foobar', and another subform would be in the 'baz'
>>>> element of that array, you'd set the subform's elementsBelongTo property
>>>> to 'foobar[baz]' --- and so on, down the tree (I show an additional
>>>> level in the example).
>>>>
>>>> The best part? if you don't need this feature, everything continues to
>>>> work as it has. :-)
>>>>
>>>> Without further ado, here's a sample form I've been working with:
>>>>
>>>>   $form = new Zend_Form();
>>>>   $form->setElementsBelongTo('foobar')
>>>>        ->setTranslator($translate);
>>>>
>>>>   $form->addElement('text', 'firstName')
>>>>        ->getElement('firstName')
>>>>        ->setLabel('First Name')
>>>>        ->setRequired(true);
>>>>
>>>>   $form->addElement('text', 'lastName')
>>>>        ->getElement('lastName')
>>>>        ->setLabel('Last Name')
>>>>        ->setRequired(true);
>>>>
>>>>   $subForm = new Zend_Form_SubForm();
>>>>   $subForm->setElementsBelongTo('foobar[baz]');
>>>>   $subForm->addElement('text', 'email')
>>>>           ->getElement('email')
>>>>           ->setLabel('Email Address');
>>>>
>>>>   $subSubForm = new Zend_Form_SubForm();
>>>>   $subSubForm->setElementsBelongTo('foobar[baz][bat]');
>>>>   $subSubForm->addElement('checkbox', 'home')
>>>>              ->getElement('home')
>>>>              ->setLabel('Home address?');
>>>>   $subForm->addSubForm($subSubForm, 'subSub');
>>>>
>>>>   $form->addSubForm($subForm, 'sub')
>>>>       ->addElement('submit', 'save', array('value' => 'submit'))
>>>>       ->setView($view);
>>>>
>>>>   echo $form, "\n\n";
>>>>
>>>>   $data = array('foobar' => array(
>>>>       'firstName' => 'Mabel',
>>>>       'lastName'  => 'Cow',
>>>>       'baz'    => array(
>>>>           'email' => '[hidden email]',
>>>>           'bat'   => array(
>>>>               'home' => 1,
>>>>           )
>>>>       )
>>>>   ));
>>>>
>>>>   echo "Data validating:\n", var_export($data, 1), "\n\n";
>>>>   echo "Result: ", var_export($form->isValid($data), 1), "\n\n";
>>>>   echo "Retrieved values:\n", var_export($form->getValues()), "\n";
>>>>
>>>> Let's look at some sample output. First, the firstName element:
>>>>
>>>>   <dt><label for="foobar-firstName" class="required">First
>>>> Name</label></dt>
>>>>   <dd>
>>>>       <input type="text" name="foobar[firstName]" id="foobar-firstName"
>>>> value="" />
>>>>   </dd>
>>>>
>>>> Notice that the name and ID are properly formatted; this was working
>>>> before. now let's look at the 'email' element:
>>>>
>>>>   <dt><label for="foobar-baz-email" class="optional">Email
>>>> Address</label></dt>
>>>>   <dd>
>>>>       <input type="text" name="foobar[baz][email]" id="foobar-baz-email"
>>>> value="" />
>>>>   </dd>
>>>>
>>>> Notice that this is now in a *SUBARRAY*! Guess what? it works for
>>>> arbitrary depth -- look at the 'home' element:
>>>>
>>>>   <dt><label for="foobar-baz-bat-home" class="optional">Home
>>>> address?</label></dt>
>>>>   <dd>
>>>>       <input type="hidden" name="foobar[baz][bat][home]" value="0"
>>>>       /><input type="checkbox" name="foobar[baz][bat][home]"
>>>>       id="foobar-baz-bat-home" value="1"  />
>>>>   </dd>
>>>>
>>>> (Yes, I know there's an issue with checkboxes... ignore that for now.)
>>>>
>>>> Now, what about retrieving values? The fun part is that the returned
>>>> values will mimic exactly the array I pass in (except that the returned
>>>> values will also contain the 'save' element).
>>>>
>>>> If you're using array notation in forms, please give this a test, and
>>>> let me know your mileage.
>>
>> --
>> Matthew Weier O'Phinney
>> PHP Developer            | [hidden email]
>> Zend - The PHP Company   | http://www.zend.com/
>
> --
>
> Simon Mundy | Director | PEPTOLAB
>
> """ " "" """""" "" "" """"""" " "" """"" " """"" "  """""" "" "
>
> 202/258 Flinders Lane | Melbourne | Victoria | Australia | 3000
> Voice +61 (0) 3 9654 4324 | Mobile 0438 046 061 | Fax +61 (0) 3 9654 4124
> http://www.peptolab.com
>

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

Mark39282
In reply to this post by weierophinney
On Saturday 09 February 2008 04:05, Matthew Weier O'Phinney wrote:
> -- Simon Mundy <[hidden email]> wrote
> > BTW, I take it there's no support for non-associative notation (e.g.
> > foo[] = 'A', foo[] = 'B')
>
> That would simply mean that the value coming into the element is an
> array, and it would be up to the element validators and filters to
> handle it.

I am interested in Simon's question specifically because I've got numerous  
tables and I've subclassed Zend_DB_Table_Abstract to give me automated CRUD
(by sniffing on $info), and to get to the point, I'm also using MySQL's 'set'
data type which in dynamically creating forms presents the issue of legal
HTML control names unless non-associative notation is used. Or, at least, I
thought it would!

Please consider this:

create table...
`activities` set('walking tours','boat rides')
Note these set element members would not be legal form control names:
http://www.w3.org/TR/html401/types.html#type-cdata

Even so, I tried implementing this with an associative array approach as in:

$form = new Zend_Form();
$form->setAction($_SERVER['PHP_SELF']);
$form->setView($view);
$form->addElement('text', 'firstName')
        ->getElement('firstName')
        ->setLabel('First Name')
        ->setRequired(true);
       
$subForm = new Zend_Form_SubForm();
$subForm->setLegend('Activities');
$subForm->addElement('checkbox', 'walking tours')
        ->getElement('walking tours')
        ->setLabel('walking tours');
$subForm->addElement('checkbox', 'boat rides')
        ->getElement('boat rides')
        ->setLabel('boat rides');
       
$form->addSubForm($subForm, 'activities')
    ->addElement('submit', 'save', array('value' => 'submit'))
    ->setView($view);

echo $form, "\n\n";

Interestingly I note the resulting HTML has the spaces removed:

<input type="checkbox" name="activities[walkingtours]"
id="activities-walkingtours" value="" />

I guess the problem with this is I need to map the non-spaced versions to back
to the spaced versions when saving to the DB. Maybe that's not such a big
deal but I wonder if I it would be better to implement non-associative arrays
to avoid the problem altogether. In which case, I didn't quite grasp
Matthew's answer to Simon. Could Matthew/anyone please elaborate on this?

Thanks in advance,
Mark



Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

weierophinney
Administrator
-- Mark Maynereid <[hidden email]> wrote
(on Saturday, 16 February 2008, 03:13 PM +0000):

> On Saturday 09 February 2008 04:05, Matthew Weier O'Phinney wrote:
> > -- Simon Mundy <[hidden email]> wrote
> > > BTW, I take it there's no support for non-associative notation (e.g.
> > > foo[] = 'A', foo[] = 'B')
> >
> > That would simply mean that the value coming into the element is an
> > array, and it would be up to the element validators and filters to
> > handle it.
>
> I am interested in Simon's question specifically because I've got numerous  
> tables and I've subclassed Zend_DB_Table_Abstract to give me automated CRUD
> (by sniffing on $info), and to get to the point, I'm also using MySQL's 'set'
> data type which in dynamically creating forms presents the issue of legal
> HTML control names unless non-associative notation is used. Or, at least, I
> thought it would!

First off, try out the current trunk, as there are a lot of improvements
and simplifications to array notation for both Zend_Form and the various
form view helpers.

As to your other notes...

> Please consider this:
>
> create table...
> `activities` set('walking tours','boat rides')
> Note these set element members would not be legal form control names:
> http://www.w3.org/TR/html401/types.html#type-cdata
>
> Even so, I tried implementing this with an associative array approach as in:
>
> $form = new Zend_Form();
> $form->setAction($_SERVER['PHP_SELF']);
> $form->setView($view);
> $form->addElement('text', 'firstName')
>         ->getElement('firstName')
>         ->setLabel('First Name')
>         ->setRequired(true);
>        
> $subForm = new Zend_Form_SubForm();
> $subForm->setLegend('Activities');
> $subForm->addElement('checkbox', 'walking tours')
>         ->getElement('walking tours')
>         ->setLabel('walking tours');
> $subForm->addElement('checkbox', 'boat rides')
>         ->getElement('boat rides')
>         ->setLabel('boat rides');

You might want to try the new 'MultiCheckbox' element (and its
corresponding view helper) for this. It allows you to specify a single
element with many options, which will output a number of labelled
checkboxes. I think you'll get better traction with that then the sub
form you're using above.

>        
> $form->addSubForm($subForm, 'activities')
>     ->addElement('submit', 'save', array('value' => 'submit'))
>     ->setView($view);
>
> echo $form, "\n\n";
>
> Interestingly I note the resulting HTML has the spaces removed:

This is documented. Element, sub form, and display group names can
contain only valid variable name characters so that overloading can
work. All other characters are stripped during normalization to ensure
this works.

> <input type="checkbox" name="activities[walkingtours]"
> id="activities-walkingtours" value="" />
>
> I guess the problem with this is I need to map the non-spaced versions
> to back to the spaced versions when saving to the DB. Maybe that's not
> such a big deal but I wonder if I it would be better to implement
> non-associative arrays to avoid the problem altogether. In which case,
> I didn't quite grasp Matthew's answer to Simon. Could Matthew/anyone
> please elaborate on this?

--
Matthew Weier O'Phinney
PHP Developer            | [hidden email]
Zend - The PHP Company   | http://www.zend.com/
Reply | Threaded
Open this post in threaded view
|

Re: Improved array support for Zend_Form

Mark39282
Thanks Matthew. I' hadn't spotted the Multicheckbox addition. It is just what
I needed.

However, I don't think it allows you to set the individual checkboxes'
attributes. I just tried to implement this with an $optionsAttrs property in
Zend_Form_Element_Multi but quickly realised I was simply duplicating almost
every method in the file and so dumped it in case there is a better way.

On another point, I think displayable attributes in general (alt/title) are
not getting translated unless I missed where it happens.

On Saturday 16 February 2008 16:08, Matthew Weier O'Phinney wrote:

> -- Mark Maynereid <[hidden email]> wrote
>
> (on Saturday, 16 February 2008, 03:13 PM +0000):
> > On Saturday 09 February 2008 04:05, Matthew Weier O'Phinney wrote:
> > > -- Simon Mundy <[hidden email]> wrote
> > >
> > > > BTW, I take it there's no support for non-associative notation (e.g.
> > > > foo[] = 'A', foo[] = 'B')
> > >
> > > That would simply mean that the value coming into the element is an
> > > array, and it would be up to the element validators and filters to
> > > handle it.
> >
> > I am interested in Simon's question specifically because I've got
> > numerous tables and I've subclassed Zend_DB_Table_Abstract to give me
> > automated CRUD (by sniffing on $info), and to get to the point, I'm also
> > using MySQL's 'set' data type which in dynamically creating forms
> > presents the issue of legal HTML control names unless non-associative
> > notation is used. Or, at least, I thought it would!
>
> First off, try out the current trunk, as there are a lot of improvements
> and simplifications to array notation for both Zend_Form and the various
> form view helpers.
>
> As to your other notes...
>
> > Please consider this:
> >
> > create table...
> > `activities` set('walking tours','boat rides')
> > Note these set element members would not be legal form control names:
> > http://www.w3.org/TR/html401/types.html#type-cdata
> >
> > Even so, I tried implementing this with an associative array approach as
> > in:
> >
> > $form = new Zend_Form();
> > $form->setAction($_SERVER['PHP_SELF']);
> > $form->setView($view);
> > $form->addElement('text', 'firstName')
> >         ->getElement('firstName')
> >         ->setLabel('First Name')
> >         ->setRequired(true);
> >
> > $subForm = new Zend_Form_SubForm();
> > $subForm->setLegend('Activities');
> > $subForm->addElement('checkbox', 'walking tours')
> >         ->getElement('walking tours')
> >         ->setLabel('walking tours');
> > $subForm->addElement('checkbox', 'boat rides')
> >         ->getElement('boat rides')
> >         ->setLabel('boat rides');
>
> You might want to try the new 'MultiCheckbox' element (and its
> corresponding view helper) for this. It allows you to specify a single
> element with many options, which will output a number of labelled
> checkboxes. I think you'll get better traction with that then the sub
> form you're using above.
>
> > $form->addSubForm($subForm, 'activities')
> >     ->addElement('submit', 'save', array('value' => 'submit'))
> >     ->setView($view);
> >
> > echo $form, "\n\n";
> >
> > Interestingly I note the resulting HTML has the spaces removed:
>
> This is documented. Element, sub form, and display group names can
> contain only valid variable name characters so that overloading can
> work. All other characters are stripped during normalization to ensure
> this works.
>
> > <input type="checkbox" name="activities[walkingtours]"
> > id="activities-walkingtours" value="" />
> >
> > I guess the problem with this is I need to map the non-spaced versions
> > to back to the spaced versions when saving to the DB. Maybe that's not
> > such a big deal but I wonder if I it would be better to implement
> > non-associative arrays to avoid the problem altogether. In which case,
> > I didn't quite grasp Matthew's answer to Simon. Could Matthew/anyone
> > please elaborate on this?
12