\documentclass{article}
\usepackage{ulem}
\usepackage{graphicx}
\usepackage{hyperref}
\pagestyle{headings}
\begin{document}
\part{Horde\_Form}
\section{What form input types are there?}
See <a href="https://wiki.horde.org/Doc/Dev/FormTypes">Doc/Dev/FormTypes</a>.

\section{Filling a form with values}
The following code could be used to fill a form through Horde\_Form, for example to edit a record. The example is a bit abstracted from reality, in that you would also need to build some validation around this code, checking for a form submission, etc. to eventually have a useable form.

For using the below examples, consider Horde application "myapp" with page "form.php":

<pre><code>
<?php
require\_once \_\_DIR\_\_ . '/lib/Application.php';
Horde\_Registry::appInit('myapp');


\$page\_output->header(array(
    'title' => \_("My Page"),
));

//
// Example code goes here
//

\$page\_output->footer();
</code></pre>

\noindent\rule{\textwidth}{1pt}
Here are some examples for introducing features of Horde\_Forms:


\noindent\rule{\textwidth}{1pt}
A simple form to get started.

<pre><code class="language-php">
// Example 1: a simple form

// Set up this data as a new Horde\_Form\_Vars object.
\$vars = Horde\_Variables::getDefaultVariables();
if (!\$vars->exists('example\_foo')) \{
    \$vars->set('example\_foo', 'Foo Sample Data');
\}

// Get formname var to check if submitted later on.
\$formname = \$vars->get('formname');

// Get the form object, setting the vars and the title.
\$myform = new Horde\_Form(\$vars, \_("An Example Form"), 'some\_form');

// Set up the form fields.
\$myform->addHidden('', 'example\_hidden', 'int', false);
\$myform->addVariable(\_("Foo field"), 'example\_foo', 'text', true);
\$myform->addVariable(\_("Bar field"), 'example\_bar', 'longtext', true, false, \_("You have to fill in some long text here"), array(4, 40));
\$myform->addVariable(\_("Make editable"), 'example\_edit', 'monthdayyear', false);
\$myform->setButtons('Abschicken', true);

// Check if form submitted and validate.
if (\$formname) \{
    if (\$myform->validate(\$vars)) \{
        \$myform->getInfo(\$vars, \$info);

        // Do something with this form data.
        echo 'saving data<br />';
    \}
\}

// Render out the form.
\$myform->renderActive(new Horde\_Form\_Renderer(), \$vars, 'form.php', 'post');
</code></pre>

\noindent\rule{\textwidth}{1pt}
\section{Using Horde\_Form\_Action}
Here's an example that uses the conditional\_enable action to enable a text description if the user picks "Other".

<pre><code class="language-php">
// Example 2: conditional enable

\$vars = Horde\_Variables::getDefaultVariables();
\$myform = new Horde\_Form(\$vars, 'Using conditional enable');

\$choices = array('big' => 'BIG',
                 'small' => 'small',
                 'other' => 'Other');
\$myform->addVariable('Select something', 'choices', 'enum', true, false, '', array(\$choices, true));
\$o = \&\$myform->addVariable('If other, please describe', 'other\_text', 'text', false, false);

// \$o is a Horde\_Form\_Variable
\$params = array('target' => 'choices',        // variable name on which the enable state depends
                'values' => array('other'), // values of target on which to change state
                'enabled' => true);        // state if variable contains one of the values
// assign an action to the variable
\$o->setAction(Horde\_Form\_Action::factory('ConditionalEnable', \$params));
// action defined through Horde\_Form\_Action\_<action> class

// Render out the form.
\$myform->renderActive(new Horde\_Form\_Renderer(), \$vars, 'form.php', 'post');
</code></pre>

\noindent\rule{\textwidth}{1pt}
<pre><code>
// Example 3: validating parameters

\$vars = Horde\_Variables::getDefaultVariables();
\$myform = new Horde\_Form(\$vars, 'A simple form');

\$myform->setButtons('Submit this form', true);
\$myform->addVariable('Insert some text', 'some\_text', 'text', true, false, 'Insert in this box some text');

\$choices = array('big' => 'BIG',
                 'small' => 'small',
                 'mixed' => 'mIxED');
\$myform->addVariable('Select something', 'choices', 'enum', false, false, 'Use the selection box to make your choice', array(\$choices, true));

if (\$myform->validate(\$vars)) \{
    \$myform->getInfo(\$vars, \$info);
    echo 'You have submitted:<br /><pre>';
    var\_dump(\$info);
    echo '</pre>';
\}

// Render out the form.
\$myform->renderActive(new Horde\_Form\_Renderer(), \$vars, 'form.php', 'post');
</code></pre>

\noindent\rule{\textwidth}{1pt}
<pre><code class="language-php">
// Example 4: a chain of forms

class TestForm1 extends Horde\_Form \{

    var \$\_useFormToken = false;

    function TestForm1(\&\$vars)
    \{
        parent::\_\_construct(\$vars, \_("Step 1")); // \_() for gettext()
       
        \$enum = array('' => \_("Select:"),
                      1 => \_("Yes"),
                      0 => \_("No"));

        // addVariable( Visible Text, name, type, required, readonly,
        // description, params)
        \$this->addVariable(\_("Enum"), 'opciones', 'enum', false, false, \_("Simple description"), array(\$enum));
        \$this->addVariable(\_("Boolean"), 'bool', 'boolean', false, false );
        \$this->addVariable(\_("Integer"), 'number', 'int', true, false );
        \$this->addVariable(\_("A Date"), 'mybday', 'date', false, false );
    \}

\}

class TestForm2 extends Horde\_Form \{

    var \$\_useFormToken = false;

    function TestForm2(\&\$vars)
    \{
        parent::\_\_construct(\$vars, \_("Step 2"));

        \$this->addVariable(\_("Email"), 'email\_address', 'email', true, false );
    \}

\}

\$r = new Horde\_Form\_Renderer();
\$vars = Horde\_Variables::getDefaultVariables();

\$form1 = new TestForm1(\$vars);
\$form2 = new TestForm2(\$vars);

\$form1Valid = \$form1->validate(\$vars, true); // Form1 can be autofilled: highlight incorrect fields right away
\$form2Valid = \$form2->validate(\$vars);

// Check if one form is not valid.
if (!\$form1Valid || !\$form2Valid) \{
    if (\$form1Valid) \{
        \$form2->open(\$r, \$vars, 'form.php', 'post');

        // show fields of Form1 as inactive
        \$r->beginInactive(\$form1->getTitle());
        \$r->renderFormInactive(\$form1, \$vars);
        \$r->end();

        // include TestForm1 variables as invisible form elements
        \$form1->preserve(\$vars);

        // render TestForm2 as active
        \$r->beginActive(\$form2->getTitle());
        \$r->renderFormActive(\$form2, \$vars);
        \$r->submit();
        \$r->end();
        \$form2->close(\$r);
    \} else \{
        \$form1->open(\$r, \$vars, 'form.php', 'post');

        \$r->beginActive(\$form1->getTitle());
        \$r->renderFormActive(\$form1, \$vars);
        \$r->submit();
        \$r->end();

        \$form1->close(\$r);
    \}
\} else \{
    \$form1->getInfo(\$vars, \$info);
    \$form2->getInfo(\$vars, \$info);
    echo '<pre>';
    print\_r(\$info);
    echo '</pre>';
\}
</code></pre>
\section{Horde\_Form design issues}
\subsection{Constructors}
some PHP 4 constructors are left

Fix:

\subsection{singletons}
Construct \& pass dependencies. There should be no reason for a singleton.<br />
Fix:

\subsection{inheritance + method signature mismatch}
\begin{itemize}
\item Form\_Type's init() pseudo constructor


\end{itemize}
Fix:

\begin{itemize}
\item Use proper constructors


\item Provide a builder with a fluent interface?


\end{itemize}
\subsection{inconsistent class names}
\begin{itemize}
\item lowercase field types<br />
Fix:


\item Namespaces and structured class names


\end{itemize}
\subsection{Internally uses the Horde:: shortcuts (separate package, hard to test)}
Fix:

\subsection{Multiple classes in one file}
\begin{itemize}
\item Most field types are attached to the Horde\_Form\_Type base package.<br />
Fix:


\item one class per file


\end{itemize}
\subsection{Extensive use of reference signatures}
Fix: Check if we really need these.

\subsection{hard-coupled javascript}
\begin{itemize}
\item parts rely on scriptaculous and hence prototypjs


\item parts rely on redboxjs<br />
Fix:


\item check if we can factor out the JS


\end{itemize}
\subsection{Uses globals}
\begin{itemize}
\item registry


\item injector


\item session


\item browser


\end{itemize}
\subsection{uses var keyword}
\begin{itemize}
\item At least in renderer


\end{itemize}
\subsection{Autowire-unfriendly constructors}
\begin{itemize}
\item untyped variables and array parameters


\end{itemize}
\subsection{Anatomy}
A Horde\_Form has <a href="https://wiki.horde.org/FormVariables">FormVariables</a>.<br />
A <a href="https://wiki.horde.org/HordeForm">HordeForm</a> may have sections.<br />
A <a href="https://wiki.horde.org/HordeForm">HordeForm</a> may use tokens to validate interactions.<br />
A <a href="https://wiki.horde.org/HordeForm">HordeForm</a> may emit <a href="https://wiki.horde.org/FormErrors">FormErrors</a> for submitted state which is invalid/inconsistent.<br />
It is displayed through a <a href="https://wiki.horde.org/FormRenderer">FormRenderer</a> either in "active" (usage) or inactive (readonly) presentation.<br />
<a href="https://wiki.horde.org/FormVariables">FormVariables</a> have <a href="https://wiki.horde.org/FormTypes">FormTypes</a>.<br />
<a href="https://wiki.horde.org/FormVariables">FormVariables</a> have references back to their Form.<br />
<a href="https://wiki.horde.org/FormVariables">FormVariables</a> may have <a href="https://wiki.horde.org/FormActions">FormActions</a> such as submit the form, <a href="https://wiki.horde.org/ConditionalEnable">ConditionalEnable</a> another Variable.

\end{document}
