Source code in Qf2ValidTypesSm.php

To see how this is used return to this tutorial index.

<?php
    // This is a form that demonstrates one of every type of input field that QuickForm2 knows about.
    // It prints out what results from the form being filled in, the form is not pretty and the
    // data doesn't make a lot of sense.

    // This is essentialy the same as Qf2ValidTypes.php but uses smarty as the display engine.
    // You should view this with: Qf2ValidTypes.tpl

    // This is QuickForm2 - without any attempt at QF1 compatability.

    // This should be considered work in progress since there are things about QF2 that I don't
    // fully understand.

    // Copyright (c) 2009, Parliament Hill Computers (www.phcomp.co.uk). Author: Alain D D Williams (addw@phcomp.co.uk).
    // You may used this file as the basis your own (or organisation's/company's) project (under whatever
    // licence that you see fit), but may not claim ownership or copyright of the substantially unmodified file.
    // This file is made available in the hope that it is useful, there is no warranty at all, use at your own risk.

    // SCCS: %W% %G% %U%

    require_once "HTML/QuickForm2.php";

    // Create a GET form with the name QfDemo:
    $form = new HTML_QuickForm2('QfDemo', 'post');
    $form->setAttribute('enctype', 'multipart/form-data');    // Needed for 'file' upload

    // When the form has been filled in, trim spaces from all fields:
    $form->addRecursiveFilter('trim');

    // Elements are added to the form with:
    //    addElement(elementOrType, elementName, attributes, data)
    // this returns an object, you only need to assign it if you want to call a method.
    // attributes are put directly into the html, things like 'value', 'size', 'width', 'onclick',
    //    what works depends on the input field, see:
    //        https://www.w3.org/TR/html401/interact/forms.html#edef-INPUT
    // data is interpretted by QF2, generic ones:
    //    'label'    A lable to the left of the input field '<label class=element'
    //                this can also be set with ->setLabel('Lable Text')
    //    'content'  Aka label to the right of the input field '<label' - containing div is class=element, after '<input'
    //               This is shown in a few cases below
    //    'name' & 'id' are in here (getName setName getId setId), also 'type' (of input field)
    //    ?? 'selected' 'disabled'

    // Text - one line of text
    // attributes:
    //    'size' how big the box is
    //    'maxlength' max # chars that can be entered, will scroll if greater than 'size'
    //    'value' an initial value, or use addDataSource()
    // Returned as a string keyed by the field name ('Age') in the array $res from getValue()
    // $age = $form->addElement('text', 'Age', array('maxlength' => 3, 'size' => 3, 'value'=> 99), array('label' => 'Age'));
    $age = $form->addElement('text', 'Age', array('maxlength' => 3, 'size' => 3), array('label' => 'Age'));
    $age->addRule('regex', 'The age must be a number', '/^[\d]+$/');

    // Text area - multiple line text box
    // attributes:
    //    'rows' - number of lines, can be exceeded
    //    'cols' - columns wide, can be exceeded
    // This gets returned as a string with embedded newlines
    // Set an initial value with addDataSource() as shown below
    $msg = $form->addElement('textarea', 'Msg', array('cols' => 30, 'rows' => 3), array('label' => 'Message'));

    // Password - like text, but the text does not show when typed
    // attributes and return value as with Text
    $form->addElement('password', 'Passwd', null, array('label' => 'Password'));
    $form->addPassword('pass2')->setLabel('Another password');


    // Add a drop down select list, one value may be chosen:
    // This generates <select> with several <option>
    // attributes:
    // data:
    //    'options'  a list of drop down values
    // Returned value as a number indexing from 0. Set default with addDataSource() as shown below
    $Titles = array('Please select', 'Mr', 'Mrs', 'Miss', 'Dr');
    $title = $form->addElement('select', 'Title', null, array('label' => 'Title', 'options' => $Titles));

    // You can addOptgroup() - I don't understand

    // Multiple select - several values may be chosen:
    // attributes:
    //    'multiple' allow multiple to be selected
    //    'size'     number displayed at one time
    // See select above.
    // Returned value an array of numbers with values indexing from 0.
    $mtit = $form->addElement('select', 'MultTitle', array('multiple' => 'multiple', 'size' => 3),
        array('label' => 'Multiple Title', 'options' => $Titles));

    // Checkbox - several can have the same name and are set/unset independently
    // attributes:
    //    'value'   the value returned when this checkbox is selected
    //    'checked' box will be initialised with a tick in it
    // data:
    //    'label' - OK it is a generic one, but you really need it here
    // Doesn't seem to work, just get the last one, this may be fixed, for now specify
    // the element names in arrray syntax
    //  $form->addElement('checkbox', 'vegetable', array('value' => 1), array('label' => 'carrot'));
    $form->addElement('checkbox', 'vegetable[0]', array('value' => 1), array('label' => 'carrot'));
    // pea is checked when the form is first displayed:
    $form->addElement('checkbox', 'vegetable[1]', array('value' => 2, 'checked' => 1), array('label' => 'pea'));
    $form->addElement('checkbox', 'vegetable[2]', array('value' => 3), array('label' => 'bean', 'content' => 'baked ?'));

    // This is just to show that the field name index can be something other than numeric:
    $form->addElement('checkbox', 'hue[pink]', array('value' => 'h_red'), array('label' => 'colour', 'content' => 'Red'));
    $form->addElement('checkbox', 'hue[lime]', array('value' => 'h_green'), array('label' => 'colour', 'content' => 'Green'));

    // Radio buttons, choose only one value - the others are unset when a new one is chosen
    // attributes:
    //    'value' is what is returned - need to give. This will be used as a key in the 'elements' array
    //         in the smarty array for this input field. Must always be given.
    //    'checked' may be set to (eg) '1' to specify the one that is initially checked,
    // Can also use setAttribute() - both are shown here
    // data:
    //    'label' appears to the left of the clickable radio button, optional - but you ought to have
    //    'content' appears to the right, is optional
    // This will appear in the rendered array as an array, with keys like 'Weekdays-1'.
    $Wdays = array('Mon' => 'Monday', 'Tue' => 'Tuesday', 'Wed' => 'Wednesday', 'Thu' => 'Thursday',
        'Fri' => 'Friday', 'Sat' => 'Saturday', 'Sun' => 'Sunday');
    // Generate a radio button for every day of the week, Tuesday's will be pre set:
    foreach($Wdays as $d => $day)
        if($d == 'Tue')
            $tue = $form->addElement('radio', 'Weekdays', array('value' => $d, 'checked'=>1),
                array('label' => "Day $day", 'content' => "content: $d"));
        else
            $form->addElement('radio', 'Weekdays', array('value' => $d),
                array('label' => "Day $day", 'content' => "content: $d"));
    // This will always make it checked, even when processing the form, don't do it:
    //    $tue->setAttribute('checked');

    // Buttons - reset (sets the form back to initial state) and submit (send form to server)
    // attributes:
    //    'value' - the text that will appear inside the button, can't use setValue()
    //    'onsubmit' - you prob don't want to do this as QF will use this once client
    //            side validation is implemented
    // data:
    //    'label' - you probably don't want to set this
    $form->addElement('reset', 'Clear');
    $form->addElement('submit', 'Submit', array('value' => 'Press to Submit'));

    // We want to have another Submit button also with the form field name 'Submit'. This is commonly done.
    // Specify a different key for the Smarty array so that the template can refer to it:
    $form->addElement('submit', 'Submit', array('value' => 'Submit and Print'), array('SmartyKey' => 'SubmitP'));

    // This is an alternate way of creating a 'reset' or 'submit' button, you will want to
    // use this if you want something more complicated than just text as the button,
    // eg an image. You can also have a 'button' that you tie javascript to with 'onclick'
    // attributes:
    //    'type' to be values 'reset', 'submit' or 'button' (the latter does nothing innate)
    // data:
    //    'content' what appears inside the button, this is any HTML that you wish

    // This button shows a javascript alert when it is pressed.
    // This generates the '<button' tag, not an '<input' field.
    $form->addElement('button', 'click', array('onclick' => 'alert("you pressed me");', 'type' => 'button'),
        array('content' => 'Go on: <b>press&nbsp;me!</b>'));

    // A submit button with HTML as a label, you could include an image here:
    $form->addElement('button', 'Enter', array('type' => 'submit'),
        array('content' => 'To submit: <b>press&nbsp;me!</b>'));

    // inputbutton - generates an input field of type button.
    // attributes:
    //    'value'    contents of the button - straight text, not general HTML
    //    'onclick'  what happens when it is pressed
    $form->addElement('inputbutton', 'Click', 
        array('value' => 'Press me please', 'onclick' => 'alert("You did it");'))->setLabel('Generate popup');

    // hidden - a way of getting an extra value to the script after submission, if not using sessions
    // attributes:
    //    'value'    the value for the next script, or use setValue()
    $form->addElement('hidden', 'invis', array('value' => 'invisible value'));
    $form->addElement('hidden', 'unseen')->setValue('unseen value');
    $form->addHidden('not_seen')->setValue('not seen value');


    // image - when this is clicked the form is submitted & coordinates returned
    // attributes:
    //    'src'    URL of the image
    //    'alt'    Describe the image - for accessibility
    // data:
    //    'label'  Perhaps tell the user what to do
    // The x and y coordinates (in pixels) of where the user clicked are returned in $res as an array,
    // indicies ['x'] and ['y']. NB: in $_GET and $_POST they are ['grid_x'] and ['grid_y'].
    $form->addElement('image', 'grid', array('src' => 'GridImage.jpg', 'alt' => 'click on coordinates'),
        array('label' => '200x100 image<br />Click to submit the form returning the x &amp; y coordinates' .
            ' of where you clicked the image'));


    // file - upload a file from the user (client)
    // data:
    //    'label'  Perhaps tell the user what the file is for
    // The form must me a 'post' form -- not 'get' (ie when you instantiate the $form object)
    // For this to work you must have: setAttribute('enctype', 'multipart/form-data')
    // The file will be read in to a temp file and the 'picture' member of $res will
    // have the elements:
    //    'name'     File name on the user's PC
    //    'type'     Mime type
    //    'tmp_name' the name of the temp file on the server
    // also 'error' and 'size'.
    $form->addElement('file', 'picture', null, array('label' => 'Give me a picture'));

    // Fieldset - fields visually grouped, ebmedded in <fieldset> tag
    // This contains any of the other fields with their normal attributes and return
    // The idea is to provide some grouping on the web page, use it to contain related items
    // You prob don't need this with smarty, fieldsets don't have names ('bankDets' below is lost)
    // so use the 'id', you may want to setOption('key_id') if you want to specify the key.
    $fset = $form->addElement('fieldset', 'bankDets', array('id' => 'bank'))->setLabel('Bank Details');
    $fset->addElement('text', 'ac_name')->setLabel('Account name');
    $fset->addElement('text', 'sort')->setLabel('Sort code');
    $fset->addElement('text', 'account')->setLabel('Account number');
    // Fieldsets nest:
    // The field names don't have to start 'bank_', but it might help understandig
    $bank_addr = $fset->addElement('fieldset')->setLabel('Bank Address');
    $bank_addr->addElement('text', 'bank_street_addr')->setLabel('Street Address');
    $bank_addr->addElement('text', 'bank_town')->setLabel('Town');
    $bank_addr->addElement('text', 'bank_postcode')->setLabel('Post Code');

    // group -- this sets up a <fieldset id="grpFset">
    // Within that there is one <div class="row"> that contains all the fields
    // setSeparator() is put between the elements of the group, the 'id' here seems to be ignored
    // Names of elements within a group must be matchable by the RE '[\w_]+'.
    $group = $form->addElement('group', 'inGrp', array('id' => 'igrp'))->setSeparator('<br class="foo"/>');
    // The fields will be given names like 'inGrp[F1]'
    $F1 = $group->addElement('text', 'F1');    // 'id' will be F1-0
    $F2 = $group->addElement('text', 'F2', array('id' => 'F2'));    // 'id' will be 'F2'
    $F3 = $group->addElement('text', 'F3')->setLabel('F3 Label');
    $F4grp = $group->addElement('group', 'F4grp'); // A group within a group
    $F5 = $group->addElement('text', 'F5');
    $F4_1 = $F4grp->addElement('text', 'F4_1')->setLabel('F4_1 Label');
    $F4_2 = $F4grp->addElement('text', 'F4_2');    // Results in smarty var: inGrp[F4grp][F4_2] (unless key_id)

    // First time round this results in false, remember that, as is common in php, this
    // script is used both to generate the form and to process the results.
    if ($form->validate()) {
        # Get here when the form has been filled in and validation checks passed
        // $form->freeze(); // If we want the form redisplayed in the way that the user entered it
        // but you need to do another display()
        $res = $form->getValue();
        echo "Title = " . htmlspecialchars($res['Title']) . " = '" . $Titles[$res['Title']] . "'<br>\n";

        echo "<pre>\n";
        echo "<p>Contents of <b>\$res</b>\n";   echo htmlspecialchars(print_r($res, 1));
        echo "<p>Contents of <b>\$_POST</b>\n"; echo htmlspecialchars(print_r($_POST, 1));
        echo "<p>Contents of <b>\$_FILE</b>\n"; echo htmlspecialchars(print_r($_FILE, 1));
        echo "</pre>\n";
        exit;
    } else {
        $form->addDataSource(new HTML_QuickForm2_DataSource_Array(
            array(
                'Msg' => "how\nnow brown\ncow",
                'Age' => 123,
                'Title' => 2))); // only does something with empty form
    }

    // require_once 'HTML/QuickForm/Renderer/ArraySmarty.php';
    require_once 'HTML/QuickForm2/Renderer.php';
    require_once 'Smarty.class.php';

    // Create the template object
    $tpl = new \Smarty;
    $tpl->template_dir = '.';       // Where the template files live
    // Smarty 'compiles' the .tpl and creates a .php script to generate the html
    // Next time smarty will use the .php without recompilation if the .tpl has not changed
    // This will live in the templates_c directory.
    // This templates_c/XXXXX.php is run to produce html
    // We could cache this html but that would mean that we would not see error messages or other things
    // that are dynamically genereated. Do not switch on caching.

    // Create the renderer object
    // $renderer = new HTML_QuickForm_Renderer_ArraySmarty($tpl);
    HTML_QuickForm2_Renderer::register('smarty', 'HTML_QuickForm2_Renderer_Smarty');
    $renderer = HTML_QuickForm2_Renderer::factory('smarty');

    // See the comments at the start of the file Smarty.php and in Qf2ValidTypes.tpl

    // Cause errors to be grouped under a pseudo field called 'errors'. This will be
    // an array where, if a field has an error, the message will be found using the
    // key 'id' or 'name' of the field (see 'key_id' option below). This makes it easy
    // to generate all of the errors in one place - if that is what you want.
    $renderer->setOption('group_errors', true);

    // Generate styles/output compatible with the old renderer (for old templates):
    // $renderer->setOption('old_compat', true);

    // Use this if you want the field keys in $FormData to be the 'id' rather than 'name'.
    // This applies for errors as well.
    // $renderer->setOption('key_id', true);

    // The old Smarty renderer produced a string 'requirednote' that could be produced.
    // This is called 'required_note' in QF2. You may set the string as below - which is default.
    // It will be edited to be in a 'div class="reqnote"'. Old smarty it has the * styled red.
    // $renderer->setOption('required_note', '<em>*</em> denotes required fields.');

    // build the HTML for the form
    $FormData = $form->render($renderer)->toArray();
    $FormData['debug'] = false;    // Debug/trace flag to smarty

    $FormData['DemoHeader'] = 'QuickForm2 Valid Types Demo';    // Form title
    $tpl->assign('FormData', $FormData);
    //print_r($FormData);exit;
    // Parse and display the template, use a different template if a GET argument is present.
    // One of the templates iterates over all the form elements (as an array) the other
    // deals with them individually (ie it knows what fields are in the form):
    $tpl->display(isset($_GET['ByElement']) ? 'Qf2ValidTypesByElement.tpl' : 'Qf2ValidTypes.tpl');


    // Uncomment these for debug:
    // echo "<b>toArray()</b><pre>"; echo htmlspecialchars(print_r($FormData, 1));echo "</pre>";
    // echo "<b>form</b><pre>";var_dump($form);echo "</pre>";

Return to this tutorial index.