\documentclass{article}
\usepackage{ulem}
\pagestyle{headings}
\begin{document}
\part{ Horde\_Form}
\tableofcontents

\section{ What form input types are there?}
See Doc/Dev/FormTypes\footnote{http://example.com/index.php?page=Doc/Dev/FormTypes}.

\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":

\begin{verbatim}

<?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();

\end{verbatim}


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


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

\begin{verbatim}

// 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');

\end{verbatim}


\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".

\begin{verbatim}

// 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');
\end{verbatim}


\noindent\rule{\textwidth}{1pt}
\begin{verbatim}

// 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');

\end{verbatim}


\noindent\rule{\textwidth}{1pt}
\begin{verbatim}

// 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>';
}
\end{verbatim}

\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.\newline
Fix:

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

Fix:\newline
- Use proper constructors\newline
- Provide a builder with a fluent interface?

\subsection{ inconsistent class names}
- lowercase field types\newline
Fix:\newline
- Namespaces and structured class names

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

\subsection{ Multiple classes in one file}
- Most field types are attached to the Horde\_Form\_Type base package.\newline
Fix:

- one class per file

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

\subsection{ hard-coupled javascript}
- parts rely on scriptaculous and hence prototypjs\newline
- parts rely on redboxjs\newline
Fix:

- check if we can factor out the JS

\subsection{ Uses globals}
- registry \newline
- injector\newline
- session\newline
- browser

\subsection{ uses var keyword}
- At least in renderer

\subsection{ Autowire-unfriendly constructors}
- untyped variables and array parameters

\subsection{ Anatomy}
A Horde\_Form has FormVariables\footnote{http://example.com/index.php?page=FormVariables}.\newline
A HordeForm\footnote{http://example.com/index.php?page=HordeForm} may have sections.\newline
A HordeForm\footnote{http://example.com/index.php?page=HordeForm} may use tokens to validate interactions.\newline
A HordeForm\footnote{http://example.com/index.php?page=HordeForm} may emit FormErrors\footnote{http://example.com/index.php?page=FormErrors} for submitted state which is invalid/inconsistent.\newline
It is displayed through a FormRenderer\footnote{http://example.com/index.php?page=FormRenderer} either in "active" (usage) or inactive (readonly) presentation.\newline
FormVariables\footnote{http://example.com/index.php?page=FormVariables} have FormTypes\footnote{http://example.com/index.php?page=FormTypes}.\newline
FormVariables\footnote{http://example.com/index.php?page=FormVariables} have references back to their Form.\newline
FormVariables\footnote{http://example.com/index.php?page=FormVariables} may have FormActions\footnote{http://example.com/index.php?page=FormActions} such as submit the form, ConditionalEnable\footnote{http://example.com/index.php?page=ConditionalEnable} another Variable.

\end{document}
