Forms status

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Forms status

weierophinney
Administrator
Hey, all --

I'm zeroing in on the requirements for the Forms component for the beta4
release. At this time:

 * The InputFilter component is feature complete, and includes both
   programmatic creation as well as using a Factory.
 * The Form component core is complete, and includes:
   * Elements, which aggregate attributes and validation messages
   * Fieldsets, which can aggregate Elements and Fieldsets, as well as
     attributes and validation messages
   * Forms, which aggregate elements and fieldsets, as well as an input
     filter. You can bind objects to it, which basically means that if
     validation succeeds, that object will be hydrated with the
     validated data. (Hydrators can be attached to match the specific
     hydration scenario your object needs.)
   * Factory for creating any/all of the above, including nested
     fieldsets.
 * Form view helpers are in progress; I've completed the Form,
   FormLabel, FormElementErrors, FormInput, and FormTextarea view
   helpers at this time, and plan to add Select support, and multiple
   Radio/Checkbox support. If there's time, and no later than beta5, I
   plan to support HTML5 specialized input types as well.

If you have access to the AgileZen board, and want to help out, the
current story I'm working, Form View Helpers, is here:

    https://agilezen.com/project/33552/story/48

On the roadmap, but not necessarily for beta4:

 * The ability for elements to hint which filters/validators should be
   used by default.
 * The ability to use annotations in a "model" object to specify element
   attributes, filters, and validators.
 * Aggregate view helpers -- view helpers that combine functionality of
   multiple view helpers to build complex markup. (Similar to how
   decorators worked previously.)
 * Support for elements with complex behavior (i.e., elements that
   combine metadata, validation, and state) : CSRF protection, CAPTCHA,
   etc.

The branch I'm working on is here:

    https://github.com/weierophinney/zf2/tree/feature/forms

There are definitely rough edges, and a few use cases I need to hammer
out (as already noted), but it's definitely ready for folks to start
playing with. Feel free to send me feedback directly!

--
Matthew Weier O'Phinney
Project Lead            | [hidden email]
Zend Framework          | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
Reply | Threaded
Open this post in threaded view
|

Re: Forms status

macest
This post has NOT been accepted by the mailing list yet.
I've been playing around with the new form stuff, looking good. I had to patch a few things to get it to work properly in some cases:

1. Radio helper always added checked attribute which meant all options were always checked.

Zend\Form\View\Helper\FormMultiCheckbox (line 153)
  foreach ($options as $label => $value) {
      $attributes['value']   = $value;
-     $attributes['checked'] = '';
      if (in_array($value, $values, true)) {
          $attributes['checked'] = 'checked';
      }
+     else {
+         unset($attributes['checked']);
+     }

      $label = $escapeHelper($label);

2. Similar case for the select helper, option attributes were always set.

Zend\Form\View\Helper\FormSelect (line 133)
  foreach ($options as $optionSpec) {
-     $value    = '';
-     $label    = '';
-     $selected = false;
-     $disabled = false;

      if (isset($optionSpec['options']) && is_array($optionSpec['options'])) {
          $optionStrings[] = $this->renderOptgroup($optionSpec, $selectedOptions);
          continue;
      }

+     $attributes = array();
+     $label = '';

      if (isset($optionSpec['value'])) {
-         $value = $optionSpec['value'];
+         $attributes['value'] = $optionSpec['value'];
      }
      if (isset($optionSpec['label'])) {
          $label = $optionSpec['label'];
      }
      if (isset($optionSpec['selected'])) {
-         $selected = $optionSpec['selected'];
+         $attributes['selected'] = $optionSpec['selected'];
      }
      if (isset($optionSpec['disabled'])) {
-         $disabled = $optionSpec['disabled'];
+         $attributes['disabled'] = $optionSpec['disabled'];
      }

      if (in_array($optionSpec['value'], $selectedOptions, true)) {
-         $selected = true;
+         $attributes['selected'] = true;
      }

-     $attributes = compact('value', 'selected', 'disabled');
      $this->validTagAttributes = $this->validOptionAttributes;
      $optionStrings[] = sprintf(
          $template, 
          $this->createAttributesString($attributes), 
          $escape($label)
      );
  }

3. I propose switching the bulk of the code from the multicheckbox helper with the radio one as the multicheckbox one needs array notation on the end of the name ("foo[]") and it is logical as it allows more than one option selected over the radio's single selection.

4. Explicit label support on the radio and multicheckbox helpers, implicit labels being the default behavior:

Zend\Form\View\Helper\MultiCheckbox
+ protected $labelImplicit = true;
+ 
+ /**
+  * Set label implicit
+  *
+  * @param boolean labelImplicit
+  */
+ public function setLabelImplicit($labelImplicit)
+ {
+     $this->labelImplicit = (bool) $labelImplicit;
+     return $this;
+ }
+ 
+ /**
+  * Get label implicit
+  *
+  * @return boolean
+  */
+ public function getLabelImplicit()
+ {
+     return $this->labelImplicit;
+ }

(Line 145)
- $template       = $labelOpen . '%s%s' . $labelClose;
  $combinedMarkup = array();
  
  foreach ($options as $label => $value) {
      $attributes['value']   = $value;
      if (in_array($value, $values, true)) {
          $attributes['checked'] = 'checked';
      }
      else {
          unset( $attributes['checked'] );
      }
  
      $label = $escapeHelper($label);
      $input = sprintf(
          '<input %s%s', 
          $this->createAttributesString($attributes), 
          $closingBracket
      );
  
      switch ($labelPosition) {
          case self::LABEL_PREPEND:
-             $markup = sprintf($template, $label, $input);
+             if ( $implicit ) {
+                 $markup = $labelOpen . $label . $input . $labelClose;
+             }
+             else {
+                 $markup = $labelOpen . $label . $labelClose . $input;
+             }
              break;
          case self::LABEL_APPEND:
          default:
-             $markup = sprintf($template, $input, $label);
+             if ( $implicit ) {
+                 $markup = $labelOpen . $input . $label . $labelClose;
+             }
+             else {
+                 $markup = $input . $labelOpen . $label . $labelClose;
+             }
              break;
      }
  
      $combinedMarkup[] = $markup;
  }

5. There doesn't seem to be anyway of setting any methods on the view helper as the invoke method calls the render method and returns the rendered markup.

Might I suggest adding an optional options parameter to the invoke method:

public function __invoke(ElementInterface $element, $options=array()) {

Then we can do the following:

echo $this->formMultiCheckbox( $form->get( 'test' ), array( 'labelImplicit' => false ) )

6. I can't seem to get the required validation to work for radio, multicheckbox or checkbox.

Just a few things I've picked up on, I will keep testing.
Reply | Threaded
Open this post in threaded view
|

Re: Forms status

macest
This post has NOT been accepted by the mailing list yet.
In reply to this post by weierophinney
Few more things:

1. Wrong attribute name on textarea helper:

Zend\Form\View\Helper\FormTextarea (line 74)

- $content            = (string) $element->getAttribute('content');
+ $content            = (string) $element->getAttribute('value');

2. Input filter uses it's built in isRequired and allowEmpty methods for elements that don't submit a value, but these have no messages to output. Therefore I suggest using the NotEmpty validator to achieve the same thing as it's duplicating functionality.

Zend\InputFilter\InputFilter (line 143)

- if (!isset($this->data[$name])) {
-     // Not sure how to handle input filters in this case
-     if ($input instanceof InputFilterInterface) {
-         $input->setData(array());
-         if (!$input->isValid()) {
-             $this->invalidInputs[$name] = $input;
-             $valid = false;
-             continue;
-         }
-         $this->validInputs[$name] = $input;
-         continue;
-     }
- 
-     // no matching value in data
-     // - test if input is required
-     // - test if input allows empty
-     if (!$input->isRequired()) {
-         $this->validInputs[$name] = $input;
-         continue;
-     }
- 
-     if ($input->allowEmpty()) {
-         $this->validInputs[$name] = $input;
-         continue;
-     }
- 
-     // How do we mark the input as invalid in this case?
-     // (for purposes of a validation error message)
- 
-     // Mark validation as having failed
-     $this->invalidInputs[$name] = $input;
-     $valid = false;
-     if ($input->breakOnFailure()) {
-         // We failed validation, and this input is marked to
-         // break on failure
-         return false;
-     }
-     continue;
- }
  
- $value = $this->data[$name];
+ $value = isset( $this->data[$name] ) ? $this->data[$name] : null;

3. I added a checkbox helper, though setting a default value on the element will always make it checked so it needs a bit of work if you want to allow custom values:

namespace Zend\Form\View\Helper;

use Zend\Form\View\Helper\FormInput as Helper;
use Zend\Form\ElementInterface;

class FormCheckbox extends Helper
{
    public function render(ElementInterface $element)
    {
        $name   = $element->getName();
        if (empty($name)) {
            throw new Exception\DomainException(sprintf(
                '%s requires that the element has an assigned name; none discovered',
                __METHOD__
            ));
        }

        $attributes         = $element->getAttributes();
        $attributes['name'] = $name;
        $attributes['type'] = 'checkbox';
        if ( !is_null( $element->getAttribute( 'value' ) ) ) {
            $attributes['checked'] = true;
        }

        return sprintf(
            '<input %s%s', 
            $this->createAttributesString($attributes), 
            $this->getInlineClosingBracket()
        );
    }
}
Reply | Threaded
Open this post in threaded view
|

Re: Forms status

weierophinney
Administrator
This post has NOT been accepted by the mailing list yet.
In reply to this post by macest
-- From macest, 1 May 2012 08:54
> I've been playing around with the new form stuff, looking good. I had
> to patch a few things to get it to work properly in some cases:
>
> 1. Radio helper always added checked attribute which meant all options
>    were always checked.

This is fixed in my branch currently.

> 2. Similar case for the select helper, option attributes were always
>    set.

Same.

> 3. I propose switching the bulk of the code from the multicheckbox
>    helper with the radio one as the multicheckbox one needs array
>    notation on the end of the name ("foo[]") and it is logical as it
>    allows more than one option selected over the radio's single
>    selection.

I'll need to address the [] notation for the multicheckbox. However,
I'm not sure it really matters which of the two helpers has the bulk of
the code, so much as they both use it (re-use is good!).

> 4. Explicit label support on the radio and multicheckbox helpers,
>    implicit labels being the default behavior:

I disagree, as this adds complexity and forces the introduction of
additional DOM identifiers, which can pose issues particularly for those
manipulating or interacting with their forms via JavaScript.

The HTML spec says that if a <label> element does not wrap an <input>,
<select>, or <textarea>, it must include a "for" attribute referencing
the element _identifier_ in the DOM.

Basically, to enable this, we'd have to generate an ID per option. What
identifier would we use? "$name-$index"? What happens if there are two
forms on the page both composing an element with the same $name -- what
happens with those IDs?

By keeping the labels implicit (i.e., wrapping the input), we eliminate
those issues, keep the markup semantic, and prevent ID collisions.

> 5. There doesn't seem to be anyway of setting any methods on the view
>    helper as the invoke method calls the render method and returns the
>    rendered markup.

Actually, there is a way, due to the new view architecture:

    $helper = $this->plugin('helper_name');
    $helper->setSomeOption();

> 6. I can't seem to get the required validation to work for radio,
>    multicheckbox or checkbox.

Can you provide a sample, please?

Thanks a ton for your feedback!

--
Matthew Weier O'Phinney
Project Lead            | matthew@zend.com
Zend Framework          | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
Reply | Threaded
Open this post in threaded view
|

Re: Forms status

weierophinney
Administrator
This post has NOT been accepted by the mailing list yet.
In reply to this post by macest
-- From macest, 3 May 2012 07:37:
> 1. Wrong attribute name on textarea helper:
>
> Zend\Form\View\Helper\FormTextarea (line 74)
>
> - $content            = (string) $element->getAttribute('content');
> + $content            = (string) $element->getAttribute('value');

Already fixed on my branch.

> 2. Input filter uses it's built in isRequired and allowEmpty methods
>    for elements that don't submit a value, but these have no messages to
>    output. Therefore I suggest using the NotEmpty validator to achieve
>    the same thing as it's duplicating functionality.

I've debated this myself -- the NotEmpty validator was actually
developed when I did the original Zend_Form implementation for precisely
the purpose of marking required elements with a message. With the new
ValidatorChain functionality, since we can specify priority, this may
actually be the simplest solution; I'll look into it today.

<snip>

> 3. I added a checkbox helper, though setting a default value on the
>    element will always make it checked so it needs a bit of work if you
>    want to allow custom values:

I plan to create some specific implementations for the various <input>
types in the future; I've been primarily hammering out the basic
functionality for this beta.

If you want to help implement these, submit pull requests against my
branch, or, once merged to master, against the project repository.
Please be sure to include tests!

Thanks again for the feedback!

--
Matthew Weier O'Phinney
Project Lead            | matthew@zend.com
Zend Framework          | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
Reply | Threaded
Open this post in threaded view
|

Re: Forms status

macest
This post has NOT been accepted by the mailing list yet.
In reply to this post by weierophinney
weierophinney wrote
> 4. Explicit label support on the radio and multicheckbox helpers,
>    implicit labels being the default behavior:

I disagree, as this adds complexity and forces the introduction of
additional DOM identifiers, which can pose issues particularly for those
manipulating or interacting with their forms via JavaScript.

The HTML spec says that if a <label> element does not wrap an <input>,
<select>, or <textarea>, it must include a "for" attribute referencing
the element _identifier_ in the DOM.

Basically, to enable this, we'd have to generate an ID per option. What
identifier would we use? "$name-$index"? What happens if there are two
forms on the page both composing an element with the same $name -- what
happens with those IDs?

By keeping the labels implicit (i.e., wrapping the input), we eliminate
those issues, keep the markup semantic, and prevent ID collisions.
Surely you would get the naming conflict with two text input elements in two forms and the same name on each as well?

> 5. There doesn't seem to be anyway of setting any methods on the view
>    helper as the invoke method calls the render method and returns the
>    rendered markup.

Actually, there is a way, due to the new view architecture:

    $helper = $this->plugin('helper_name');
    $helper->setSomeOption();
Ah, thanks.

> 6. I can't seem to get the required validation to work for radio,
>    multicheckbox or checkbox.

Can you provide a sample, please?
This was solved by item 2 from my previous post.
Reply | Threaded
Open this post in threaded view
|

Re: Forms status

weierophinney
Administrator
This post has NOT been accepted by the mailing list yet.
macest wrote
weierophinney wrote
> 4. Explicit label support on the radio and multicheckbox helpers,
>    implicit labels being the default behavior:

I disagree, as this adds complexity and forces the introduction of
additional DOM identifiers, which can pose issues particularly for those
manipulating or interacting with their forms via JavaScript.

The HTML spec says that if a <label> element does not wrap an <input>,
<select>, or <textarea>, it must include a "for" attribute referencing
the element _identifier_ in the DOM.

Basically, to enable this, we'd have to generate an ID per option. What
identifier would we use? "$name-$index"? What happens if there are two
forms on the page both composing an element with the same $name -- what
happens with those IDs?

By keeping the labels implicit (i.e., wrapping the input), we eliminate
those issues, keep the markup semantic, and prevent ID collisions.
Surely you would get the naming conflict with two text input elements in two forms and the same name on each as well?
The main point, however, is that the potential for conflict and error is much higher when we automate ID generation as we would need to do for this situation. Since the labels and inputs are not separated by even whitespace, it makes no sense to NOT wrap the input in the label, and prevents such conflict/error potential.
Reply | Threaded
Open this post in threaded view
|

Re: Forms status

Mohammad ZeinEddin
In reply to this post by weierophinney
On Sat, Apr 21, 2012 at 12:48 AM, Matthew Weier O'Phinney <[hidden email]> wrote:
Hey, all --

I'm zeroing in on the requirements for the Forms component for the beta4
release. At this time:

 * The InputFilter component is feature complete, and includes both
  programmatic creation as well as using a Factory.
 * The Form component core is complete, and includes:
  * Elements, which aggregate attributes and validation messages
  * Fieldsets, which can aggregate Elements and Fieldsets, as well as
    attributes and validation messages
  * Forms, which aggregate elements and fieldsets, as well as an input
    filter. You can bind objects to it, which basically means that if
    validation succeeds, that object will be hydrated with the
    validated data. (Hydrators can be attached to match the specific
    hydration scenario your object needs.)
  * Factory for creating any/all of the above, including nested
    fieldsets.
 * Form view helpers are in progress; I've completed the Form,
  FormLabel, FormElementErrors, FormInput, and FormTextarea view
  helpers at this time, and plan to add Select support, and multiple
  Radio/Checkbox support. If there's time, and no later than beta5, I
  plan to support HTML5 specialized input types as well.

If you have access to the AgileZen board, and want to help out, the
current story I'm working, Form View Helpers, is here:

   https://agilezen.com/project/33552/story/48

On the roadmap, but not necessarily for beta4:

 * The ability for elements to hint which filters/validators should be
  used by default.
 * The ability to use annotations in a "model" object to specify element
  attributes, filters, and validators.
 * Aggregate view helpers -- view helpers that combine functionality of
  multiple view helpers to build complex markup. (Similar to how
  decorators worked previously.)
 * Support for elements with complex behavior (i.e., elements that
  combine metadata, validation, and state) : CSRF protection, CAPTCHA,
  etc.

The branch I'm working on is here:

   https://github.com/weierophinney/zf2/tree/feature/forms

There are definitely rough edges, and a few use cases I need to hammer
out (as already noted), but it's definitely ready for folks to start
playing with. Feel free to send me feedback directly!

--
Matthew Weier O'Phinney
Project Lead            | [hidden email]
Zend Framework          | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc


Hi Matthew, all:
I have been following your discussions in this mailing list since a couple of months, at my work we are considering to start a very BIG database driven project and we almost agreed to use Zend, our project has multiple DB in the backend (Oracle, Postgres and Mysql), and we were wondering when will -mainly- oracle support be ready? and do you think that using "Doctrine Project" for our project will be a better choice?

Best Regards,
Mohammad ZeinEddin
Reply | Threaded
Open this post in threaded view
|

Re: Forms status

weierophinney
Administrator
This post has NOT been accepted by the mailing list yet.
-- mohammad [via Zend Framework Community] <[hidden email]> wrote
(on Monday, 14 May 2012, 04:46 AM -0700):
> On Sat, Apr 21, 2012 at 12:48 AM, Matthew Weier O'Phinney <[hidden email]>
> wrote:

<snip>

> I have been following your discussions in this mailing list since a couple of
> months, at my work we are considering to start a very BIG database driven
> project and we almost agreed to use Zend, our project has multiple DB in the
> backend (Oracle, Postgres and Mysql), and we were wondering when will -mainly-
> oracle support be ready? and do you think that using "Doctrine Project" for our
> project will be a better choice?

We're pushing oracle support to beta5 at the earliest, and potentially
to the 2.1 release (that and DB2 require specialized knowledge and
testing infrastructure). It's possible that you can use Oracle via its
PDO extension already, but you'd need to test.

Doctrine is quite different than Zend\DB. While it provides a DB
abstraction layer, to my knowledge, support for non-PDO drivers is
minimal and not as well tested. Additionally, the DBAL is primarily
targetted at ORM operations, and may or may not be suited for general
consumption.

In short, you'll likely need to test both Zend\Db and Doctrine DBAL
carefully to ensure they suit your particular application needs.


--
Matthew Weier O'Phinney
Project Lead            | [hidden email]
Zend Framework          | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
Reply | Threaded
Open this post in threaded view
|

Re: Forms status

Wil Moore III
This post has NOT been accepted by the mailing list yet.
Doctrine is quite different than Zend\DB.

True statement.
 
support for non-PDO drivers is minimal and not as well tested.

This statement is inadvertently misleading actually...

The Doctrine2 DBAL (database abstraction & access layer) project is developed separately and used by the ORM. The DBAL is a PDO abstraction and tries to stay compatible with that API; however, it isn't limited to PDO-only support. The adapter system allows for even non-PDO custom drivers. For example, Oracle support is brought in via the oci8 extension…but you still use the PDO-like API. It's quite clean IMHO.


The cool thing is that DBAL includes a database introspection API as well. For example, it is powerful enough to power the database migrations tool.


In other words, If you didn't care about using an ORM, you could use the Doctrine2 DBAL to great effect on its own.
 
targetted at ORM operations, and may or may not be suited for general consumption.

Largely, the ORM is made up of:

In short, you'll likely need to test both Zend\Db and Doctrine DBAL carefully to ensure they suit your particular application needs.

Absolutely true. Test both and figure out which will work better for you.


--
Wil Moore III

Best Practices for Working with Open-Source Developers
http://www.faqs.org/docs/artu/ch19s02.html

Why is Bottom-posting better than Top-posting:
http://www.caliburn.nl/topposting.html

DO NOT TOP-POST and DO trim your replies:
http://linux.sgms-centre.com/misc/netiquette.php#toppost
Reply | Threaded
Open this post in threaded view
|

Re: Forms status

weierophinney
Administrator
This post has NOT been accepted by the mailing list yet.
-- Wil Moore III [via Zend Framework Community] <[hidden email]> wrote
(on Monday, 14 May 2012, 09:47 AM -0700):

>     Doctrine is quite different than Zend\DB.
>
> True statement.
>  
>     support for non-PDO drivers is minimal and not as well tested.
>
> This statement is inadvertently misleading actually...
>
> The Doctrine2 DBAL (database abstraction & access layer) project is developed
> separately and used by the ORM. The DBAL is a PDO abstraction and tries to stay
> compatible with that API; however, it isn't limited to PDO-only support. The
> adapter system allows for even non-PDO custom drivers. For example, Oracle
> support is brought in via the oci8 extension…but you still use the PDO-like
> API. It's quite clean IMHO.

Ah, okay -- I knew for quite some time that it only targetted PDO, but
if that's no longer the case, I stand corrected.

> https://github.com/doctrine/dbal/tree/master/lib/Doctrine/DBAL/Platforms
> https://github.com/doctrine/dbal/tree/master/lib/Doctrine/DBAL/Driver
>
> The cool thing is that DBAL includes a database introspection API as well. For
> example, it is powerful enough to power the database migrations tool.
>
> https://github.com/doctrine/dbal/tree/master/lib/Doctrine/DBAL/Schema
>
> In other words, If you didn't care about using an ORM, you could use the
> Doctrine2 DBAL to great effect on its own.

Also, good to know -- thanks for the clarifications, Wil!

--
Matthew Weier O'Phinney
Project Lead            | [hidden email]
Zend Framework          | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc