Quick links: Content - sections - sub sections
EN FR

jForms stores all form data in sessions. In your controller, you'll access those data through a form object, instantiation of a class inheriting from jFormsBase. That class is automatically generated by jForms by the parsing of your XML file. As for DAO, it is stored in cache to optimize performance.

In your controller, you'll create, modify and destroy a form object with jForms static methods.

Forms and actions

As described in Classic forms, you are advised to create a set of actions to manage a form completely (name of actions below are not mandatory of course, you could use which ever you want):

  • "prepare" action. its role is to create a form object with jForms, pre-fill the form if needed and redirect to "show" action.
  • "show" action. it will first get the form object and use it in a template to display its form and maybe user input errors of a preceding submit. Upon user submit, "save" action will be called.
  • "save" action. the form object is retrieved filled with user inputs through a jForms method. Then, it could check data for errors. If so, it will redirect to "show" otherwise it will process data (save it to database for example) and redirect to "end".
  • "end" action. it will destroy the form object (it will clean data stored in session), and could display a confirmation of user posting or anything else...

Create a form object

Before using jForms, it is required to have an xml descriptive file and that one of your action create a form object associated. Such object is returned form jForms::create static method.

As every other jForms static methods, its first argument is a selector of an XML file and accepts a second optional argument which is an id for your form object.

Say you have an XML file "contact.form.xml" in "main" module:


   $form = jForms::create("main~contact");

$form is an object of the class generated after parsing of XML file. that class inherit form jFormsBase. with $form, you'll have an API to manipulate form data.

In the peceding example, we don't use a second argument. As said it is optional. It is only needed if you want to display a form on some already existing data. For example, if you want to edit a product stored in database, you'll give its id to jForms.

Why? Modern browsers allow to open multiple tabs. As a result, a user could open the same product edit form more than once at the same time BUT on different products. To prevent saving data in the same session object (thus loosing inputs) for each opened form, you must set a unique id to the form object. This id can be anything (a string, a number) but generally you'll use a SQL record key.

If your XML is "product.form.php" located in shop module, here is an example of a form object creation on an existing product:


   $form = jForms::create("shop~product", $product_id);

Off course, if you want to edit a new product, no need of an id:


   $form = jForms::create("shop~product"); // new product

Now, read again our preceding example. A contact form. We did not give an id because we assert here that it will always be an empty form.

Form initialisation

After form creation, you may need to pre-fill it.

Simple initialisation

Use setData method of your form object. Give it your control name as first argument and its value as second.


  $form->setData("firstname","Laurent");

You can of course, retrieve value from a dao, a business class or anything else.

Initialisation from a dao

If you retrieve values from a dao, there is a more efficient way to fill you form. initFromDao() method allows to fill multiple form fields. Indicate a dao selector as first arg. If you don't set the second argument, it will look for a record whose id is the form id. Setting a second argument will bypass this default behaviour.


   $form = jForms::create("shop~product", $product_id);
   $form->initFromDao("shop~products");

Form will be filled with values of the record whose id is $product_id in "shop~products" dao.

However, note that only controls whose name (or ref) are the same as dao properties will be pre-filled. Others will stay untouched.

You could use more than one dao to fill your fields. Your form fields could correspond to multiple tables in database for example.

Initialisation of a multiple choice control

<checkboxes> and <listbox multiple="true"> controls could be filled with more than one value. (Beware, here we talk about values to be pre-selected and not the list if choices label).

You can still use setData by giving an array of values to pre-select:


    $form->setData('categories', array(5, 8, 10));

But, commonly, those value lists reside in database and are retrieve from a join statement. ie. a table having as primary key two or more foreign keys. each foreign key being a primary key of a different table. Imagine a table for products ('products'), a table for product categories ('categories'), and a product can belong to more than one category, you will construct a join table ('products_categories'), associating prodcut keys and category keys (product_id and category_id).

If you want to fill your listbox or your checkboxes, you should read from 'products_categories' table. jForms provide a method on your form object to achieve this initControlFromDao() :


   $form->initControlFromDao("categories", "shop~products_categories");

Of course, you should before define a "shop~products_categories" dao. jForms expects as first dao key the one identifying a product and as second one the one identifying a category. Even if it is not the case, you could give an array fo key names as third arg to initControlFromDao:


   $form->initControlFromDao("categories", "shop~products_categories", array('product_id','category_id'));

Note that this example is an edit product form. Here we assume that the form id corresponds to a product id and as so initControlFromDao will use it as search criteria to retrieve category id.

Defining choices for multiple choices controls

In jforms xml file, we have documented several ways to populate choices of a <menulist>, a <listbox>, a <radiobuttons> or a <checkboxes> controls (static data, dao, class).

Those could still be unsufficient. In that situation, declare neither <item> tag nor dao* or class attribute in you XML file. In your controller, define your choices as follow:


   // retrieve your choices in an associative array,
   $data = array(...);

   // get your control and affect its data
   $form->getControl('nom_du_control')->datasource->data = $data;

in $data, keys should be value of choices and values should be label of choices.

Note : you should do this in "show" action, ie. action that display your form.

Get an already created form

In a specific action, you have created your form object with jForms::create(), but following actions need to get the same form object. Two jForms methods for this purpose : get() and fill().

get() retrieve simply your form object. As for create(), give it a form selector:


   $form = jForms::get("shop~product");

If you had given an id on creation, you'll have to give it also to get:


   $product_id = $this->param('id'); // id has been transmitted through http
   $form = jForms::get("shop~product", $product_id);

Note : get method returns null if form does not exist. It probably means that user has mistepped action where your form was created. You should then redirect him to this action. Or directly create your form (this could prove sufficient on simple forms).


   $form = jForms::get("main~contact");
   if ($form === null) {
        $form = jForms::create("main~contact");
   }

fill() method also returns a form object (in fact it calls jForms::get()), but achieve another functionality: it fills form data with all contents received through HTTP post or get request. Clear, it should be called after user submit (see preceding section on form sumit).


   $product_id = $this->param('id');
   $form = jForms::fill("shop~product", $product_id);

Note: identifier (id here) is still transmitted manually but following jelix versions should automate this.

Treat a form after submit

Once a form has been created, it has to be displayed which is documented in a chapter apart. Then another action should process submitted data. it will be called upon user submit and should retrieve form data, check their values and process them (saving for example).

Fill your form

Remember that jForms::fill() method return your form object AND fill it with user input data:


    $form = jForms::fill("main~contact");

Which is the same as:


    $form = jForms::get("main~contact");
    $form->initFromRequest();

You can again use setData to overload user inputs or fill some empty controls for example.


    $form = jForms::get("main~contact");
    $form->setData('name', $this->param('name'));

Check data

Once you have a form object filled with submitted data, you should check precisely if this is what you expect before going on processing. check() method does basic checkings based on what you described in your XML file (if a field is required, if field data type is correct, etc...). check() returns true if all checkings pass, false otherwise.

If data validation fails, you'll generally display your form again with error messages. if you do so, check() will have automatically displayed error messages on your form and your user will have to correct them.


    $form = jForms::fill("main~contact");
    if (!$form->check()) {
        // invalid: redirect to "show" action
        $rep = $this->getResponse('redirect');
        $rep->action='module~default:show';
        return $rep;
    }

You can, of course, implement more complex checkings on data. In order to access control data, call getData method. In order to set an error on a particular field, use setErrorOn.


    $form = jForms::fill("main~contact");
    if (!$form->check()) {
        // invalid : redirect to "show" action
        $rep = $this->getResponse('redirect');
        $rep->action='module~default:show';
        return $rep;
    }
    $ok = true;
    $valeur = $form->getData('nom');
    if( strpos($value, 'qwerty') !== null) {
        $ok = false;
        $form->setErrorOn('name', 'you should spell your real name !');
    }
     // other checks
     //....

    if (!$ok) {
        // invalid : redirect to "show" action
        $rep = $this->getResponse('redirect');
        $rep->action='module~default:show';
        return $rep;
    }

Storing data

Once all checkings are ok, you can extract data of your form object through calls of getData() method or simply getAllData() call which retrieves all form data under a PHP array. And then, you could save them to database with jDao or jDb, send some parts by mail, and so on.

Storing through DAO

Reflecting initFromDao which fills a form, saveToDao allows you to save user inputs via DAO. Values of fields whose name equals dao properties are affected to said dao, on a record. Record key is your form id. If you haven't set a form id, a new record willbe created instead of updating an existing record.


   $form->saveToDao('shop~products');

saveToDao method returns primary key of the processed record.


   $primaryKey = $form->saveToDao('shop~products');

Storing values a multiple choices control

As well as saveToDao, saveControlToDao does the opposite of initControlFromDao. It then save selected values of checkboxes or multpile choices listbox in a join table.


   $form->saveControlToDao('categories', 'shop~products_categories');

First arg is a field name and the second a dao selector which will be used for storage.

Storing files

If your form has file upload controls, you'll have to store those files upon submit. jForms API has two methods dedicated: saveFile() and saveAllFiles. The first one deals with one file and the latter deals with every file uploaded and save them in a same directory. Be aware that you'll find original filename in its control data (which you access calling getData). Use setData to modify this name if needed.

saveFile() take your control name as argument. Its default behaviour will store file in var/uploads/module_name~form_name/ folder. An optional second argument is supported to override saveFile default behaviour and store your file in your folder of choice. And a third one, if you want to modify its filename.

Example :


    $form->saveFile('photo');
    $form->saveFile('photo', JELIX_APP_WWW_PATH.'images/photos/');
    $form->saveFile('photo', JELIX_APP_WWW_PATH.'images/photos/', $id.'.png');
    $form->saveFile('photo', '', $id.'.png');

saveAllFiles copy all uploaded files to a directory. The default one is var/uploads/module_name~form_name/, but you can override it by providing a second argument:


    $form->saveAllFiles();
    $form->saveAllFiles(JELIX_APP_WWW_PATH.'images/photos/');

Destroy a form object

When a form object is no more used (inputs done, submitted, data checked and treated/stored), you are advised to destroy your form object to lighten session data. Use jForms::destroy and give it your form selector and your form id (if there is one).


   jForms::destroy("main~contact");
   jForms::destroy('shop~products');
   jForms::destroy('shop~products', $product_id);