\documentclass{article}
\usepackage{ulem}
\usepackage{graphicx}
\usepackage{hyperref}
\pagestyle{headings}
\begin{document}
\part{Horde\_Form rewrite/Horde\_Field:: Proposal}
This page is a proposal for the implementation of new package to replace Horde\_Form\_Type:: and Horde\_Form\_Variable::.

I'm refactoring this page into topics.  I had a major wiki breakthrough when doing this for work (as I receive e-mail, enter meeting notes, etc., I now factor into topics which could be different pages or different headings on a page).  A really good overview emerges fairly quickly and it works extremely well with something like a project's needs analysis.  So let's call it a pattern. -- <a href="https://wiki.horde.org/JasonFelice">JasonFelice</a>

\section{Proposed Paths/Requirements}
\subsection{Autogeneration}
Extend Rdo (<a href="http://cvs.horde.org/framework/Rdo\">http://cvs.horde.org/framework/Rdo\textbackslash\{\}</a>) and Horde\_Form to autogenerate basic CRUD forms (create, read, update, delete) based on the metadata already available in Rdo.

\subsection{Ajax Functionality}
Follow up on the Summer of Code Horde\_Form project (currently available in the incubator - <a href="http://cvs.horde.org/incubator/Horde\_Form/\">http://cvs.horde.org/incubator/Horde\textbackslash\{\}\_Form/\textbackslash\{\}</a>). Update the code to use Prototype and<br />
Scriptaculous for the scripting basis, sync with the current Horde\_Form code, and go from there. The ability to have any form switch between active and inactive rendered mode - optionally on a field-by-field basis - using in-place-edit functionality would be very slick.

\subsection{Useable Without Horde\_Form::}
There are currently still some interdependencies with Horde\_UI\_VarRenderer:: and Horde\_Form:: which really suck.  When working on Horde\_UI\_Table::, I need to render fields in display mode and I have no form. -- <a href="https://wiki.horde.org/JasonFelice">JasonFelice</a>

\subsection{No Display Assumptions}
I'm going to take the opportunity of a Text\_Wiki design discussion on the PEAR lists to propose we reorganize our whole concept of varrenderers and form types, etc.

First of all, we should clean up the form types so that they are solely conceptual - no display assumptions/logic/differences in them. No difference between radio and select lists, for example.

Then we have the field renderers/etc., one renderer per type of field (where radio and select lists *are* different) per rendering format supported (XHTML, PDF, etc).

It'd be a lot of files, which I've tried to avoid in the past, but it seems the only way to really make this flexible, and to avoid having to parse *too* much code just to get a select widget, for example. This should be useable with things like Horde\_UI\_Table, the Prefs system, the Blocks configuration, etc., too, without intrisically requiring Horde\_Form.

I'm not sure where the renderers should live in the class tree.

The Text/Wiki class tree idea that got me thinking about this again looks like<br />
so:

<pre><code>
        Text/Wiki/Parse.php

        Text/Wiki/Parse/Bold.php
        Text/Wiki/Parse/Code.php
        Text/Wiki/Parse/Wikilink.php

        Text/Wiki/Render.php

        Text/Wiki/Render/DocBook.php
        Text/Wiki/Render/DocBook/Bold.php
        Text/Wiki/Render/DocBook/Code.php
        Text/Wiki/Render/DocBook/Wikilink.php
</code></pre>
-- <a href="https://wiki.horde.org/ChuckHagenbuch">ChuckHagenbuch</a> (from e-mail on May 26, 2004)

\subsection{Multiple Output Formats}
In our old framework, we can render a field to plain text, HTML, or TeX (since that is how we produce PDFs).

Here's one question, how do we handle edit formats?  We could theoretically have a PDF edit format or a Flash edit format, or more likely some sort of embedded device markup.  If we have an output matrix of ( medium * type ), we could be talking about a lot of classes.

I propose that we just have one class per output medium, and display or edit is determined by which method is called.

-- <a href="https://wiki.horde.org/JasonFelice">JasonFelice</a>

\subsection{"Filter" Fields}
I don't know how to handle this just yet, but in our old framework, we have a Get\_Filter\_HTML() method.  For a date, it returns HTML with a start date field and an end date field (it is a possibly open-ended date range, in other words).  The field also has a Get\_Filter\_SQL() which takes a field name and returns a fragment of an SQL WHERE clause to "filter" by that expression.

In Horde, we can't assume the back end is SQL.  In the old framework, a lot of the Get\_Filter\_HTML() methods have been factored into separate field types (like a date range field, in this case), so perhaps just a method to retrieve an instance of the filter field type for this field type.  The driver model makes it difficult to automagically turn this into a query limiter, though, so it might just not be feasable for Horde.

-- <a href="https://wiki.horde.org/JasonFelice">JasonFelice</a>

\subsection{Field Representation Is Configurable}
In order to take into account different sorts of representations for the same data type, the fields can accept field-dependant config parameters (the typical \$params key/value array).  The field can use these to determine things like:

\begin{itemize}
\item How wide a text field appears.


\item Whether to use radio buttons or a drop-down for an enum.


\item etc.


\end{itemize}
-- <a href="https://wiki.horde.org/JasonFelice">JasonFelice</a>

\subsection{Scatter/Gather}
I think the field class that returns the HTML edit representation needs to have a method for "gathering" the form fields back into the internal representation.  An example could be Horde's monthdayyear field, which has three form fields for representing a date value.  The gather() method would take this data and return the internal value. -- <a href="https://wiki.horde.org/JasonFelice">JasonFelice</a>

\subsection{Careful Attention to Internal Value Representations}
We've had this problem with our old framework, and I see it to some degree in Horde.  What does a date look like?  If we could pick one form, we constrain the number of interfaces we deal with and therefore the complexity.  In our old framework, we have internal (PHP) values, database (PostgreSQL textual representation) values and HTML form values.  We assumed when first designing when we were basically just using text inputs that all of these were the same, but that got us into big touble.

In Horde, we can make sure the storage driver returns the internal form, so we seal off the database representation into the database-specific driver, which is really nice.  We currently do have a problem with the other types of values, though.  We should probably always use PEAR Date:: representations because we certainly don't want different fields for UNIX timestamp and more useful date formats.

-- <a href="https://wiki.horde.org/JasonFelice">JasonFelice</a>

\section{Unsorted Notes}
<a href="http://uipatternfactory.com/">http://uipatternfactory.com/</a><br />
<a href="http://www.lukew.com/resources/articles/PSactions.asp">http://www.lukew.com/resources/articles/PSactions.asp</a><br />
<a href="http://jeffhowden.com/code/css/forms/">http://jeffhowden.com/code/css/forms/</a><br />
<a href="http://www.frevvo.com/frevvo/web/home">http://www.frevvo.com/frevvo/web/home</a><br />
<a href="http://www.smashingmagazine.com/2006/11/11/css-based-forms-modern-solutions/">http://www.smashingmagazine.com/2006/11/11/css-based-forms-modern-solutions/</a><br />
<a href="http://www.formassembly.com/form-garden.php">http://www.formassembly.com/form-garden.php</a><br />
<a href="http://www.jamiehoover.com/?channel=journal\&amp;item=11">http://www.jamiehoover.com/?channel=journal\textbackslash\{\}\&item=11</a><br />
<a href="http://code.google.com/p/repetitionmodel/">http://code.google.com/p/repetitionmodel/</a><br />
<a href="http://www.nyphp.org/phundamentals/spoofed\_submission.php">http://www.nyphp.org/phundamentals/spoofed\textbackslash\{\}\_submission.php</a><br />
<a href="http://svn.rubyonrails.org/rails/trunk/actionpack/lib/action\_view/helpers/form\_helper.rb">http://svn.rubyonrails.org/rails/trunk/actionpack/lib/action\textbackslash\{\}\_view/helpers/form\textbackslash\{\}\_helper.rb</a><br />
<a href="http://ajaxian.com/archives/ajform-and-rejax-reloaded">http://ajaxian.com/archives/ajform-and-rejax-reloaded</a>

Horde\_Form - change tabs and tab javascript to use HTML structure from YUI:<br />
<a href="http://developer.yahoo.com/yui/tabview/">http://developer.yahoo.com/yui/tabview/</a>

Also use this for Prefs?

Also consider Ext tabs:<br />
<a href="http://www.yui-ext.com/deploy/ext-1.0-alpha3/docs/">http://www.yui-ext.com/deploy/ext-1.0-alpha3/docs/</a>

Additional tabs notes:<br />
<a href="http://developer.yahoo.com/ypatterns/pattern.php?pattern=moduletabs">http://developer.yahoo.com/ypatterns/pattern.php?pattern=moduletabs</a>

avoid serialized form data, send a checksum for it (checksum in session of course)

Horde\_View and Horde\_Form and sub-views

don't need to create new view objects!<br />
just call \$this->render() with the sub page name!<br />
view variables will be maintained

I just discovered a hole in a white list validation technique I borrowed from a<br />
PHP security book \&\#139; no, not Chris¹ book.

Beware in\_array(\$\_POST/GET[\&\#140;input¹], \$whitelist)

Type matters. All input is string type and PHP will try to force type<br />
matching.

So the input string \&\#140;securityhole¹ will match the int number 0.

horde\_form overloading:

\$form->Enum(\$name, \$desc, \$note, ... (any other params are type config options - use func\_get\_args/func\_num\_args if needed - not needed, have <u>call \$args

\$form->optionalEnum - non required<br />
\$form->requiredEnum - required<br />
which is default?

expected variables - track in the form, not the Variables object<br />
need a simplified Variables object for incubator Horde\_Form

\begin{itemize}
\item remove foo<a href="https://wiki.horde.org/bar">bar</a> syntax in favor of \$vars->foo->bar ?


\item remove expected variables, getExists, etc.


\item could just be an <a href="https://wiki.horde.org/ArrayObject">ArrayObject</a>?


\end{itemize}
Look at what should be in Type and what in Variable<br />
simplify validate() methods (rename from isValid?)

<a href="http://blog.astrumfutura.com/archives/281-Complex-Web-Pages-with-the-Zend-Framework.html">http://blog.astrumfutura.com/archives/281-Complex-Web-Pages-with-the-Zend-Framework.html</a>

Horde\_Form rewrite notes:

multienum (and checkboxes if any?) get consolidated to Set

enum, radio buttons -> enum

Horde\_Form<br />
1 class/file for autoload<br />
autoload file (all types?)<br />
Horde\_Form\_Variable\_View ?<br />
rename Variable to Field?<br />
keep type separate but make basic api as clean and small as possible<br />
Horde\_Form\_Type -> standard constructor for all types instead of factory

no singletons!

horde\_form\_type\_* -> replace about() methods with doc introspection<br />
<a href="http://us2.php.net/reflection">http://us2.php.net/reflection</a>

form descriptions - xml, db, php (the list of addVariable() calls)

TODO

Actions for buttons (not currently possible)

I know this sounds really dumb but I cant seem to find a solution for<br />
it. How do I attach an action (Horde\_Form\_Action) to a submit button<br />
in a form that is generated via the Horde\_Form class? My objective is<br />
to call a custom javascript function when the user clicks the submit<br />
button on the form.

i am currently in the need of a form-library to process form-data without the ever going<br />
hassle of boring input sanitization and validation. i read thru the Zend-Form proposal<br />
and it seems that its going to be a *big* form-creation quick-form pendant.

i coded a component to do filtering and validation only and transporting values and<br />
errors over session-namespaces to redirect between processing<->view.

the usage is like this:

<code type="php">

\begin{itemize}
\item FORM-PROCESSING<br />
\$F = new Form('edit');


\item common form-data<br />
\$F->register('type')->isTableKey('mediatype', 'mediatype\_id');<br />
\$F->register('collection')->isBool();<br />
\$F->register('parts')->isOptional()->isArray()->isTableKey('media', 'media\_id');<br />
\$F->register('lang')->isTableKey('locale', 'locale\_id');<br />
\$F->register('country')->isTableKey('locale', 'locale\_id');<br />
\$F->register('title')->isString();<br />
\$F->register('origtitle')->isString();<br />
\$F->register('comment')->isString();<br />
\$F->register('rating')->isInt(0, 5);


\item optional checklists (kind of <select multiple>)<br />
\$F->register('genres')->isOptional()->isArray()->isTableKey('genre', 'genre\_id');<br />
\$F->register('genres\_new')->isOptional()->isArray()->isString();<br />
\$F->register('persons')->isOptional()<br />
->isArray()<br />
->isTableKey('person', 'person\_id')<br />
->requires('person\_roles');<br />
\$F->register('person\_roles')->isOptional()<br />
->isArray()<br />
->isString();


\end{itemize}
\$F->register('persons\_new')->isOptional()<br />
->isArray()<br />
->isString()<br />
->requires('person\_roles\_new');

\$F->register('person\_roles\_new')->isOptional()<br />
->isArray()<br />
->isString();<br />
[...]

\begin{itemize}
\item working with Zend-Validators, -Filters and Function-Delegates


\end{itemize}
function fooDelegate(\$elementName, \$elementValue, \$formData) \{<br />
return true;<br />
\}

\$F->register('foo')->validate(new Zend\_Validate\_xxx())<br />
->filter(new Zend\_Filter\_yyy())<br />
->delegate('fooDelegate');

try \{<br />
\$this->db->beginTransaction();<br />
\$F->validate(\$\_POST);

\$title = \$F->value('title');<br />
...

if [\$persons= \$F->value('persons'](\$persons= \$F->value('persons') \{<br />
foreach (\$persons as \$personID) \{<br />
...<br />
\}<br />
\}

*or<br />
\$persons = \$F->value('persons', array());<br />
foreach (\$persons as \$personID) \{<br />
...<br />
\}

\} catch (<a href="https://wiki.horde.org/FormException">FormException</a> \$e) \{<br />
\$this->db->rollBack();<br />
print\_r(\$F->getErrors());<br />
\$this->redirect('back to edit-form-view');<br />
\}

\begin{itemize}
\item VIEW<br />
\$F = new Form('edit');<br />
if (\$F->hasErrors())<br />
print\_r(\$F->getErrors());


\end{itemize}
if (!(\$title = \$F->value('title')))<br />
\$title = '<populate from db>';

<input type=text value=\$title /><br />
</code>

API discussion:

We are in the middle of a discussion Alexey and I about <a href="https://wiki.horde.org/QuickForm2">QuickForm2</a> API for elements<br />
creation and I would like your opinion as well.<br />
At this point, nothing is immutable since we aren't even talking about alpha stage, so<br />
your preferences as users and developers is interesting.

To summarize, Alexey would be in favor of this:

\$form->addElement('button', 'aButton', 'Click me please');<br />
\$form->addElement('select', 'aSelect', array('1' => 'option 1', '2' => 'option 2'));

While I would be in favor of this:

\$form->addElement('button', 'aButton')->setContent('Click me please');<br />
\$form->addElement('select', 'aSelect')->setOptions(array('1' => 'option 1', '2' =><br />
'option 2'));

This is an example for adding a button to a form. The API can get more complex for Date<br />
elements and other javascript aided elements.

My opinion is that we shouldn't mix configuration parameters for elements with other kind<br />
of data they might need.

The other point we are discussing is about the extra parameter in element creation. I<br />
suggest we always use an array, even when there is only one extra parameter. Alexey<br />
suggests that we use a scalar if there is only one extra  parameter. For example, for a<br />
given "Year" element which would only accept one configuration parameter 'startYear',<br />
Alexey would use:

\$form->addElement('year', 'aYear', '2007');

While I would use:

\$form->addElement('year', 'aYear', array('startYear' => '2007'));

So my way is more verbose and less writable, but is also more readable and extensible.

Given these examples, are there any opinions or preferences in favor of one or the other<br />
proposed API ?<br />
Thanks in advance,

We are in the middle of a discussion Alexey and I about <a href="https://wiki.horde.org/QuickForm2">QuickForm2</a>\newline
API for elements creation and I would like your opinion as well.<br />
At this point, nothing is immutable since we aren't even talking\newline
about alpha stage, so your preferences as users and developers is\newline
interesting.

To summarize, Alexey would be in favor of this:

\$form->addElement('button', 'aButton', 'Click me please');<br />
\$form->addElement('select', 'aSelect', array('1' => 'option 1', '2'\newline
=> 'option 2'));

This is the old (and IMO sometimes confusing) style which is (at least<br />
in the current QF) not consistent through the various elements.<br />
While I would be in favor of this:

\$form->addElement('button', 'aButton')->setContent('Click me please');<br />
\$form->addElement('select', 'aSelect')->setOptions(array('1' =>\newline
'option 1', '2' => 'option 2'));

This style is more "OO-ish" (*g*) and should also be more consistent in<br />
usage.

The other point we are discussing is about the extra parameter in\newline
element creation. I suggest we always use an array, even when there\newline
is only one extra parameter. Alexey suggests that we use a scalar if\newline
there is only one extra  parameter. For example, for a given "Year"\newline
element which would only accept one configuration parameter\newline
'startYear', Alexey would use:

\$form->addElement('year', 'aYear', '2007');

While I would use:

\$form->addElement('year', 'aYear', array('startYear' => '2007'));

+1 for this last style because it avoids confusion, too, and especially<br />
also because sometimes later such elements might get a second, third,<br />
... option.

What's really being discussed is the following, will we make the "additional data"<br />
parameter that has different semantics from element to element always an array, so the<br />
first pair of calls above turns into

\$form->addElement('button', 'aButton', array('content' => 'Click me please'));<br />
\$form->addElement('select', 'aSelect', array('options' => array('1' => 'option 1', '2' =><br />
'option 2')));

even though the elements in question will never need any additional data other than<br />
'content' and 'options'.

My vote would be for always an array --- even in cases where an<br />
element will only need one piece of scalar data.

As many have already pointed out, changing from scalars to array based<br />
on the individual element leads to confusion about which elements<br />
require which parameter format --- I would even be against the<br />
flexibility of allowing both ways because I think it leads to more<br />
complicated documentation and more room for coding errors.

I've honestly found the addElement() API to be difficult to work with in<br />
the past, so simplifying it would be a welcome change.

However, I don't think "addElement" needs to exist in Quickform2.  Have<br />
you considered an API similar to the following?

<code type="php"><br />
<?php

\$form = new HTML\_Quickform2;<br />
\$form['action'] = '/path/to/action.php';<br />
\$form['method'] = 'post';

\begin{itemize}
\item or<br />
\$form['attrs'] = array('action' => '/path/to/action.php', 'method' =><br />
'post');


\end{itemize}
\$g = \$form->group['mygroup'];<br />
\$g->text = array('name' => 'aText', 'size' => 50, 'default' => 'whatever');<br />
\$g->select = array('name' => 'aSelect', 'options' => array(...));

\begin{itemize}
\item or<br />
\$g->text(array('name' => 'aText', 'size' => 50))<br />
->validate['regex'] =  '/\textbackslash\{\}w+/';<br />
\$g->select(array('name' => 'aSelect', 'options' => array())<br />
\$select = \$g->select['aSelect']; * or \$form->select['aSelect'];<br />
\$select->options['another'] = 1;<br />
\$select->validate['custom'] = 'is\_numeric';<br />
?><br />
</code>


\end{itemize}
Compare this to:

<code type="php"><br />
<?php

\$form = new HTML\_Quickform2('/path/to/action.php', 'method' => 'post');<br />
\$form->addGroup('mygroup');<br />
\$form->addElement('text', 'aText', array('size' => 50, 'default' =><br />
'whatever', 'group' => 'mygroup')<br />
->validate('regex', '/\textbackslash\{\}w+/');<br />
\$sel = \$form->addElement('select', 'aSelect', array(...));<br />
\$sel->addOption('another', 1);<br />
\$sel->validate('custom', 'is\_numeric');<br />
?><br />
</code>

In the second example, my eyes are drawn to a bunch of "add*" and it<br />
appears that the important information ('text', 'select') is secondary.<br />
It takes me a while to figure out what is actually being done.  The<br />
first example has no superfluous information, but simply sets up the<br />
form in a straightforward, no-nonsense manner.

In other words, I've always dreamed of having a simplexml-like API for<br />
accessing/creating forms.  I hate translating what I want to do into<br />
method APIs.  Think of this as bringing the REST model to forms<br />
creation, whereas everything has been XML-RPC based up to this point :).

Another feature request I've had that may be possible is to integrate<br />
some kind of forms creation cache, so that the form need only be created<br />
programmatically once, and then it can on subsequent requests be quickly<br />
recreated from a disk or database cache, skipping all the expensive<br />
method calls, but this is a separate question than the one you asked,<br />
let me know if you'd like a feature request opened on this.

If you do decide to go with the other API format, I am in favor of more<br />
explicit options (associative array/fluent).  I hate relying on Zend IDE<br />
to do auto-completion, it makes debugging far more difficult to do with<br />
just a simple text editor and eyeballs.

As an addendum to my last message, I just thought of an even clearer<br />
interface:

<?php

\$form = new HTML\_Quickform2;

\$g = \$form->group['mygroup'];

\$g->text['aText'] = array('size' => 50);<br />
\$g->select['aSelect'] = array('size' => 5', 'options' => array(...));

?>

By using <a href="https://wiki.horde.org/ArrayAccess">ArrayAccess</a> offsetSet() you can put the element name in<br />
brackets.  This way, the same procedure (array access) is used to both<br />
set and to retrieve elements.  This could also be used to modify values<br />
later if necessary, for the same element, something that I've found<br />
exceedingly difficult to do in the current QF.  Consider the following:

<?php

\$form = new HTML\_Quickform2;

\$form->text['mytext'] = array('default' => 'whatever');<br />
unset(\$form->text['mytext']);

?>

Simple and easy.

Le 16 avr. 07 ? 18:31, Gregory Beaver a Ècrit :

> \$g->text(array('name' => 'aText', 'size' => 50))<br />
>           ->validate['regex'] =  '/\textbackslash\{\}w+/';<br />
> \$g->select(array('name' => 'aSelect', 'options' => array())<br />
> \$select = \$g->select['aSelect']; * or \$form->select['aSelect'];<br />
> \$select->options['another'] = 1;<br />
> \$select->validate['custom'] = 'is\_numeric';

I like this as well. We have designed what I would call a low-level<br />
API for <a href="https://wiki.horde.org/QuickForm">QuickForm</a>. Built on top of that, it will be easier to add<br />
syntactic sugar like this at a later time.<br />
It's a bit like what jQuery and Prototype did to javascript DOM. PHP5<br />
allows this, we should indeed use it to our advantage IMO (I need to<br />
convince Alexey though :) ).

> Another feature request I've had that may be possible is to integrate<br />
> some kind of forms creation cache, so that the form need only be<br />
> created<br />
> programmatically once, and then it can on subsequent requests be<br />
> quickly<br />
> recreated from a disk or database cache, skipping all the expensive<br />
> method calls, but this is a separate question than the one you asked,<br />
> let me know if you'd like a feature request opened on this.

At the moment, I have no idea how to do that, any ideas would be<br />
welcome.<br />
The good news is that <a href="https://wiki.horde.org/QuickForm2">QuickForm2</a> should be faster than current<br />
<a href="https://wiki.horde.org/QuickForm">QuickForm</a> :)

Another feature request I've had that may be possible is to integrate<br />
some kind of forms creation cache, so that the form need only be created<br />
programmatically once, and then it can on subsequent requests be quickly<br />
recreated from a disk or database cache, skipping all the expensive<br />
method calls, but this is a separate question than the one you asked,<br />
let me know if you'd like a feature request opened on this.

At the moment, I have no idea how to do that, any ideas would be welcome.<br />
The good news is that <a href="https://wiki.horde.org/QuickForm2">QuickForm2</a> should be faster than current <a href="https://wiki.horde.org/QuickForm">QuickForm</a> :)

Hi Bertrand,

I would store element validation information in a simple array, and then<br />
use the renderer to render a PHP-based template (a la Savant) that will<br />
allow setting default values, so that the display process is basically:

<?php<br />
\$form->prepareCache();<br />
include \$form->getCacheFile();<br />
?>

Validation would work as it currently does.  You'd end up with something<br />
like:

<?php

\$form = new HTML\_Quickform2;<br />
\$form['name'] = 'whatever';<br />
if (\$form->submitted \&\& \$form->valid) \{<br />
\}<br />
if (\$form->cached) \{<br />
\$form->displayCache();<br />
\} else \{<br />
// set up the form<br />
\}<br />
?>

Things like validation errors can be handled with placeholders as well<br />
(an if() in the template that skips the error HTML).

To summarize, Alexey would be in favor of this:

\$form->addElement('button', 'aButton', 'Click me please');<br />
\$form->addElement('select', 'aSelect', array('1' => 'option 1', '2'<br />
=> 'option 2'));<br />
Well, this has worked in the past and isn't too hard to grasp if the<br />
documentation makes it clear how this works (the current docs are a<br />
bit confusing in this regard). Having the additional parameters be the<br />
constructor args for the element is a fine option. However, it's<br />
always confusing to have lots of parameters to a method and I know I<br />
never remember which is which.<br />
\$form->addElement('year', 'aYear', '2007');

While I would use:

\$form->addElement('year', 'aYear', array('startYear' => '2007'));

So my way is more verbose and less writable, but is also more<br />
readable and extensible.<br />
Extensability is a good thing. Readability is a good thing. I'd vote<br />
for an assoc array over variable numbers of arguments.<br />
Well, people aren't yet familiar with the new QF2 API and Bertrand didn't bother to give<br />
the full picture, so here goes:

We no longer have variable number of parameters to elements' constructors, since neither<br />
Bertrand nor myself were able to remember all the parameter lists, and we actually<br />
*wrote* the abomination. Every constructor is now defined as:<br />
public function </u>construct(\$name, \$data, \$label, \$attributes) \{ ... \}

Now, this what this \$data thing means changes from element to element because the<br />
elements have different needs. What's *really* being discussed here is the fact that<br />
Bertrand wants to make \$data *always* an associative array, thus

\$form->addElement('button', 'aButton', array('content' => 'Click me please'));<br />
\$form->addElement('select', 'aSelect', array('options' => array('1' => 'option 1', '2' =><br />
'option 2')));

while I suggest deciding on it on a per-element basis, thus<br />
\$form->addElement('button', 'aButton', 'Click me please');<br />
\$form->addElement('select', 'aSelect', array('1' => 'option 1', '2' => 'option 2'));

but most certainly<br />
\$form->addElement('year', 'aYear', array('startYear' => '2007'));

since that hypothetical 'year' element *may* earn additional parameters in the future<br />
which is highly unlikely in case of Buttons and Selects.

I've honestly found the addElement() API to be difficult to work with in<br />
the past, so simplifying it would be a welcome change.

However, I don't think "addElement" needs to exist in Quickform2.  Have<br />
you considered an API similar to the following?

<pre><code class="language-php">
<?php

\$form = new HTML\_Quickform2;
\$form['action'] = '/path/to/action.php';
\$form['method'] = 'post';
// or
\$form['attrs'] = array('action' => '/path/to/action.php', 'method' =>
'post');

\$g = \$form->group['mygroup'];
\$g->text = array('name' => 'aText', 'size' => 50, 'default' => 'whatever');
\$g->select = array('name' => 'aSelect', 'options' => array(...));

// or
\$g->text(array('name' => 'aText', 'size' => 50))
         ->validate['regex'] =  '/\textbackslash\{\}w+/';
\$g->select(array('name' => 'aSelect', 'options' => array())
\$select = \$g->select['aSelect']; // or \$form->select['aSelect'];
\$select->options['another'] = 1;
\$select->validate['custom'] = 'is\_numeric';
?>
</code></pre>
With all due respect, <a href="https://wiki.horde.org/SimpleXML">SimpleXML</a> API which you seem to use as inspiration here uses<br />
addAttribute() and addChild() methods for adding attributes and child nodes, it doesn't<br />
work as shown above. ;)

We considered something like that, but decided to go with DOM-like API for now.

I assume it is more consistent to always use an array and provide additional setters for<br />
all possible keys, so every element can be added in both ways:

\$form->addElement('button', 'aButton', array('content' => 'Click me', 'attributes' =><br />
array('onClick' => 'alert("Clicked!")')));

or:

\$clickbutton = \$form->addElement('button', 'aButton');<br />
\$clickbutton->setContent('Click me');<br />
\$clickbutton->setAttributes('onClick' => 'alert("Clicked!")');

Like this, every public property can actually be set on element construction.

Anyway I see an other point I want to strongly advise to rethink: It looks like the QF2<br />
API will still be quite near to the HTML syntax of every single element, which is<br />
actually not consistent across the elements and their natures. I gather this assumption<br />
from the "options" property of the select element (besides: setOptions() also confuses as<br />
this method has a totally different meaning in many other PEAR classes).

If you put your focus at interchangability of elements, you find 2 different kinds of<br />
lists, which can both have 2 different forms:

\begin{itemize}
\item List with only one element selectable:


\end{itemize}
\begin{itemize}
\item Select element with size=1 (or no size attribute)


\item Radiobutton group


\end{itemize}
\begin{itemize}
\item List with multiple selectable elements:


\end{itemize}
\begin{itemize}
\item Select element with size > 1


\item Checkbox group


\end{itemize}
IMO those should be treated identically, for example:

\$ctry = \$form->addElement('select', 'country');<br />
\$ctry->setList(array('CH' => 'Switzerland', 'FR' => 'France'));<br />
\$ctry->setContent('CH');

If you later decide to change it to a radiogroup, you just have to change the line:<br />
\$ctry = \$form->addElement('radiogroup', 'country');

Also note that I suggest to use setContent() to define the preselected option rather than<br />
something like \$option->setSelected() (which could be left as an alternative). It looks<br />
consistent to me to set the preselected value with the same method for all kinds of<br />
elements/groups, regardless of the way it looks in the generated HTML. So setContent() in<br />
a select box will result in setting the selected attribute, while it will set a value<br />
attribute if applied on a text field.

I would even make it:

\$clickbutton =<br />
\$form->addElement('button', 'aButton')->setContent('Click<br />
me')->setAttributes('onClick' => 'alert("Clicked!")');

On 4/17/07, Christoph Schiessl <<a href="https://wiki.horde.org/mailto:c.schiessl@gmx.net">c.schiessl@gmx.net</a>> wrote:

<a href="https://wiki.horde.org/Show">Quoted Text - 58 lines</a><br />
On Apr 17, 2007, at 9:58 AM, Markus Ernst wrote:<br />
Alexey Borzov schrieb:<br />
[...]<br />
What's really being discussed is the following, will we make the<br />
"additional data" parameter that has different semantics from<br />
element to element always an array, so the first pair of calls<br />
above turns into<br />
\$form->addElement('button', 'aButton', array('content' => 'Click<br />
me please'));<br />
\$form->addElement('select', 'aSelect', array('options' => array<br />
('1' => 'option 1', '2' => 'option 2')));<br />
even though the elements in question will never need any<br />
additional data other than 'content' and 'options'.<br />
I assume it is more consistent to always use an array and provide<br />
additional setters for all possible keys, so every element can be<br />
added in both ways:

\$form->addElement('button', 'aButton', array('content' => 'Click<br />
me', 'attributes' => array('onClick' => 'alert("Clicked!")')));<br />
I don't like the idea of using arrays for the additional parameters.<br />
Element creation has always been a problem for me in QF1, because<br />
there were to many possible combinations of parameters to remember<br />
all of them.<br />
or:

\$clickbutton = \$form->addElement('button', 'aButton');<br />
\$clickbutton->setContent('Click me');<br />
\$clickbutton->setAttributes('onClick' => 'alert("Clicked!")');

\section{Like this, every public property can actually be set on element<br />
construction.<br />
Looks nice. I think that would be easier to use (and to remember).<br />
Also note that I suggest to use setContent() to define the<br />
preselected option rather than something like \$option->setSelected<br />
() (which could be left as an alternative). It looks consistent to<br />
me to set the preselected value with the same method for all kinds<br />
of elements/groups, regardless of the way it looks in the generated<br />
HTML. So setContent() in a select box will result in setting the<br />
selected attribute, while it will set a value attribute if applied<br />
on a text field.<br />
Fully agree on that one.}
Markus

I cannot say I support setting variables and properties with arrays,<br />
it also have been the biggest thing that kept me away from QF for a<br />
long time.

Bertrand Mansion wrote:<br />
Hi all,

We are in the middle of a discussion Alexey and I about <a href="https://wiki.horde.org/QuickForm2">QuickForm2</a> API<br />
for elements creation and I would like your opinion as well.<br />
At this point, nothing is immutable since we aren't even talking about<br />
alpha stage, so your preferences as users and developers is interesting.

To summarize, Alexey would be in favor of this:

\$form->addElement('button', 'aButton', 'Click me please');<br />
\$form->addElement('select', 'aSelect', array('1' => 'option 1', '2' =><br />
'option 2'));

While I would be in favor of this:

\$form->addElement('button', 'aButton')->setContent('Click me please');<br />
\$form->addElement('select', 'aSelect')->setOptions(array('1' => 'option<br />
1', '2' => 'option 2'));

This is an example for adding a button to a form. The API can get more<br />
complex for Date elements and other javascript aided elements.

My opinion is that we shouldn't mix configuration parameters for<br />
elements with other kind of data they might need.

The other point we are discussing is about the extra parameter in<br />
element creation. I suggest we always use an array, even when there is<br />
only one extra parameter. Alexey suggests that we use a scalar if there<br />
is only one extra  parameter. For example, for a given "Year" element<br />
which would only accept one configuration parameter 'startYear', Alexey<br />
would use:

\$form->addElement('year', 'aYear', '2007');

While I would use:

\$form->addElement('year', 'aYear', array('startYear' => '2007'));

So my way is more verbose and less writable, but is also more readable<br />
and extensible.

Given these examples, are there any opinions or preferences in favor of<br />
one or the other proposed API ?<br />
Hi Bertrand,

I've honestly found the addElement() API to be difficult to work with in<br />
the past, so simplifying it would be a welcome change.

However, I don't think "addElement" needs to exist in Quickform2.  Have<br />
you considered an API similar to the following?

<pre><code class="language-php">
<?php

\$form = new HTML\_Quickform2;
\$form['action'] = '/path/to/action.php';
\$form['method'] = 'post';
// or
\$form['attrs'] = array('action' => '/path/to/action.php', 'method' =>
'post');

\$g = \$form->group['mygroup'];
\$g->text = array('name' => 'aText', 'size' => 50, 'default' => 'whatever');
\$g->select = array('name' => 'aSelect', 'options' => array(...));

// or
\$g->text(array('name' => 'aText', 'size' => 50))
         ->validate['regex'] =  '/\textbackslash\{\}w+/';
\$g->select(array('name' => 'aSelect', 'options' => array())
\$select = \$g->select['aSelect']; // or \$form->select['aSelect'];
\$select->options['another'] = 1;
\$select->validate['custom'] = 'is\_numeric';
?>
</code></pre>
Compare this to:

<pre><code class="language-php">
<?php

\$form = new HTML\_Quickform2('/path/to/action.php', 'method' => 'post');
\$form->addGroup('mygroup');
\$form->addElement('text', 'aText', array('size' => 50, 'default' =>
'whatever', 'group' => 'mygroup')
   ->validate('regex', '/\textbackslash\{\}w+/');
\$sel = \$form->addElement('select', 'aSelect', array(...));
\$sel->addOption('another', 1);
\$sel->validate('custom', 'is\_numeric');
?>
</code></pre>
In the second example, my eyes are drawn to a bunch of "add*" and it<br />
appears that the important information ('text', 'select') is secondary.<br />
It takes me a while to figure out what is actually being done.  The<br />
first example has no superfluous information, but simply sets up the<br />
form in a straightforward, no-nonsense manner.

In other words, I've always dreamed of having a simplexml-like API for<br />
accessing/creating forms.  I hate translating what I want to do into<br />
method APIs.  Think of this as bringing the REST model to forms<br />
creation, whereas everything has been XML-RPC based up to this point :).<br />
Using AAs for creating forms is absolutely the way to go. A huge +1<br />
for Greg's suggestions. It is exactly because of the reasons Greg<br />
mentions. The form creation and the actual display of the form should<br />
be separated completely.<br />
Another feature request I've had that may be possible is to integrate<br />
some kind of forms creation cache, so that the form need only be created<br />
programmatically once, and then it can on subsequent requests be quickly<br />
recreated from a disk or database cache, skipping all the expensive<br />
method calls, but this is a separate question than the one you asked,<br />
let me know if you'd like a feature request opened on this.<br />
This is *exactly* what Solar[1] does. You can load[2] forms (or<br />
rather, form "hints", which are just AAs) from SQL table objects and<br />
from XML files and hand them to your "view". This is *made* for MVC.

This complicated API that you suggest seems a really bad idea to me.

Anyways, just my \$0.02

[1] <a href="http://solarphp.com">http://solarphp.com</a><br />
[2] <a href="http://solarphp.com/class/Solar\_Form/load\(\)">http://solarphp.com/class/Solar\textbackslash\{\}\_Form/load\textbackslash\{\}(\textbackslash\{\})</a>

I don't find any current implementations of forms to have a true cache.<br />
The problem here is that a form is always changing.  It must respond to<br />
user input, display errors, and so on.  However, the logic of how the<br />
form is constructed is completely static.  Since the only thing we<br />
really need to be able to do is proper validation of form fields, and<br />
then to fill in a few placeholders (default value, error messages if<br />
any), this data can be cached as html, saving the need to construct a<br />
huge tree of objects.

For high-volume sites, this could provide a large gain in<br />
requests/second, whereas building the form from an array is no different<br />
from building it with method calls - except you have the added step of<br />
parsing the array.

Separating logic from view is irrelevant to my suggestion.  Quickform 1.x used renderers to do this, I suppose Quickform2 will have some facility as well.

\part{2016 thoughts}
We have at least 3 separate trains of thought with Horde\_Forms

\begin{itemize}
\item generate presentation from DB+Rdo


\item Update Horde\_Forms from H3ish PHP4ish style to PSR-autoloadable PHP5/7 OO and losen coupling of form validation and presentation


\item Something with the Ajax framework, at least as an option or addon


\end{itemize}
Currently, the recommendation from core developers for some ajax use cases is "render simple forms by hand, in a view"

\begin{itemize}
\item A form as a validation context for input in the backend does not need to be presented as a html form - it might be a table of attributes and values, becoming editable only on click


\item Free text input with autocomplete suggestions is quite common today


\item Fields may be invisible of readonly for some users based on application state or permissions


\item apps may break into popup/redbox windows for some cases of "choose existing or create new related item" or load-on-demand dialogues instead of pre-defined conditional subdialogs


\item support relations (Rdo or domain context) with little repetitive coding


\item support on-the-fly validation while typing<br />
Less coupling.


\end{itemize}
Js/dom

Anything that has a data-edit attribute is an edit trigger. A parent must have data-field (field name) and data-form (form name)<br />
is it sufficient to have any parent of parent to have data-form attribute?

Anything that has data-save is a save trigger.

Some types might need extra handlers like datepicker

Php

The ajax handler must be explicitly registered in ajax application. It guesses prefix\_formname\_fieldname classname for an injectable object. The field class has a backend and a list of validators and change propagators which are each only defined by interface to allow flexible backends with existing inheritance trees. Otherwise rdo and friends wont work here. A field class also references a type class and horde view templates for active and readonly rendering. Defaults from type, overridable. The form class might be optional for fields as any combination of fields may be displayed anytime. A form or collection with a common save trigger might still be needed to bootstrap new domain items with more than one required field... and we need some context where to store a record's key for ajax interaction. Form may change or unhide more fields depending on valid state

\end{document}
