Models - search form

This tutorial shows how to use class FormSearch to render search forms from models and then query model data from search parameters.

Note: while reading this tutorial keep in mind to always respect the HTTP POST and GET method usages. Use POST for sending data to the server and GET for retrieving data.

Creating object

$form = new FormSearch(); // default name is search
/* name the form */
$form = new FormSearch('formname');
/* to return from object to create state */

$form->reset(); // default name is search
$form->reset('newFormName');

When creating a form object a name can be specified. Naming a form will cause all widgets names inside the form to have form name as prefix. For example for a form without a name form widget names are such as: modelname-propertyname or myWidgetName but for a form with name they would become formname-modelname-propertyname and formname-myWidgetName. Naming a form can be useful when more than one forms are used in a page from the same model, to prevent form widgets from having the same tag id.

Unlike class Form, class FormSearch puts a search as name for form by default. Unless changed the form elements will be names as search-modelname-propertyname and search-myWidgetName.

Method reset clears all configs and returns form object to create state. When rendering more than one form with a form object reset the object before config up new form.

Note: when some complex widgets are used in a form, a form objects may add CSS and/or JavaScript files or JavaScript codes to factory context. For the form to work correctly this sources need to be loaded/executed after printing form HTML on the screen.

Search forms require

arta.js

to be loaded to work.

Adding widgets and inputs

Adding widgets and inputs is exactly the same as explained in Form - Adding widgets and inputs .

There is one exception! In search forms # can be added to model property list in method add:

$user = new User();
$form = new FormSearch(); // default name is search

$form->add($user, '#');

$form->add($user, '#', 'name', 'age', 'email');

$form->add($user, array('#', 'name', 'age', 'email'));

# adds a text search to the form which the value would be searched in all model properties.

Adding form and section

Adding form and section is exactly the same as explained in Form - Adding form and section .

Grouping...

Grouping is exactly the same as explained in Form - Grouping... .

Note: In search forms only use grouping on buttons and elements which. Do not put model properties into groups.

Search operators

Each row of the search form has three parts: widget.

  • label
  • operator
  • input or widget

The operator part is a select list which lets users to select a search operators.

The operators which are used are:

FormSearch::CONTAIN
FormSearch::CONTAIN_ALL
FormSearch::CONTAIN_ONE
FormSearch::EQUAL
FormSearch::EQUAL_NOT
FormSearch::IN
FormSearch::GREATER
FormSearch::LESS
FormSearch::BETWEEN

Based on model property data type or other definitions FormSearch assigns each property to one of the following groups:

FormSearch::STRING
FormSearch::CHAR
FormSearch::NUMBER
FormSearch::DATE
FormSearch::DROPDOWN
FormSearch::EXACT
FormSearch::TEXT

Each of this groups is associated to some search operators. So when a search form is being build depending in this different operators are shown for different model properties. Below is the default operator groups. This is defined as an array by property operators:

$forms->operators = array(
    FormSearch::STRING => array(
        FormSearch::CONTAIN,
        FormSearch::CONTAIN_ALL,
        FormSearch::CONTAIN_ONE,
        FormSearch::EQUAL,
    ),
    FormSearch::CHAR => array(
        FormSearch::IN,
    ),
    FormSearch::NUMBER => array(
        FormSearch::EQUAL,
        FormSearch::GREATER,
        FormSearch::LESS,
        FormSearch::EQUAL_NOT,
        FormSearch::IN,
        FormSearch::BETWEEN,
    ),
    FormSearch::DATE => array(
        FormSearch::BETWEEN,
        FormSearch::EQUAL,
        FormSearch::GREATER,
        FormSearch::LESS,
    ),
    FormSearch::TEXT => array(
        FormSearch::CONTAIN,
    ),
    FormSearch::EXACT    => array(
        FormSearch::EQUAL,
    ),
    FormSearch::DROPDOWN => array(
        FormSearch::IN,
    ),
);

Property operators is public and can be changed by the programmer to customized the operators in each group.

The first operator in the list is the default operator.

To assign fixed operators instead of operator list (default operators will only be available):

$form->params(array(
    /* disable operator select */
    'fixed' => True,
));

FormSearch::TEXT group of operators is used for # which means text search in all model properties.

In a multi lingual application operators will be translated when shown in the select lists. However by changing property translate texts (shown in operator select list) can be changed manually. Below is the default contents of property translate:

$form->translate = array(
    FormSearch::CONTAIN     => _('Contains'),
    FormSearch::CONTAIN_ALL => _('Contain All'),
    FormSearch::CONTAIN_ONE => _('Contain One'),
    FormSearch::EQUAL       => _('='),
    FormSearch::EQUAL_NOT   => _('< >'),
    FormSearch::IN          => _('In'),
    FormSearch::GREATER     => _('>'),
    FormSearch::LESS        => _('<'),
    FormSearch::BETWEEN     => _('Between'),
);

To explicitly assign an operator group to a model property use method params.

$form->params(array(
    /* change operator group for property id */
    'id' => array(
        'operator' => FormSearch::EXACT, 
    ),
));

To disable showing operator list for one or all properties use CSS.

Attributes

Config parameters is exactly the same as Form - Attributes . Except search form have search operators which can be attributed:

$form->attributes(array(
    /* set attributes for operator <td> container */
    'operator' => array(
        'name' => array('class' => 'operator-td-class',),
    )
));

Parameters

Config parameters is exactly the same as Form - Parameters .

FormSearch class accepts few parameters associated with operators, this parameters where described on the Operator section of this tutorial.

Get raw form

Method raw returns form raw data in an array:

$raw = $form->raw();

$raw = array(
    'property name' => array(
        'label',
        'widget HTML',
        'type of widget or input',
        'unique name',
        'operator widget HTML',
    ),
);
  • Array key is set to model property name or widget name (when widget is added not from model data).
  • Translated (when application is multi lingual) label to be shown before the widget.
  • Widget HTML tag or tags.
  • String showing the type of widget.
  • If widget has an id or name attribute it would be it otherwise it would be a unique string.
  • Operator select widget.

Render form as HTML

Method render renders and returns form as HTML:

$user = new User();
$form = new FormSearch();
$form->add($user, User::searchCols());
$form->button('Search', 'search();', 'search-button');
/* render form as HTML, suitable to be used in a template
   or sent by AJAX to be shown on the page */
$html = $form->render();

Rendered HTML structure will look like:

<table class="search-form-table">
  <tr class="search-all-txt">
    <td id="search-user-all-txt-td-label" class="caption">
      <label id="search-user-all-txt-label">Search for</label>
    </td>
    <td id="search-user-all-txt-td-operator" class="operator">
      <select id="search-user-all-txt-operator" class="operator-select"
              onchange="Arta.searchOperator(this);">
        <option value="C">Contains</option>
      </select>
    </td>
    <td id="search-user-all-txt-td" >
      <input name="search-user-all-txt"
             class="all-txt search-form-widget search-form-widget"
             id="search-user-all-txt"
             type="text"
             title="Search for" />
    </td>
  </tr>
  <tr>
    <td id="search-user-id-td-label" class="caption">
      <label id="search-user-id-label">ID</label>
    </td>
    <td id="search-user-id-td-operator" class="operator">
      <select id="search-user-id-operator" class="operator-select"
              onchange="Arta.searchOperator(this);">
        <option value="E">=</option>
        <option value="G">&gt;</option>
        <option value="L">&lt;</option>
        <option value="N">&lt; &gt;</option>
        <option value="I">In</option>
        <option value="B">Between</option>
      </select>
    </td>
    <td id="search-user-id-td" >
      <input class="number int search-form-widget"
             name="search-user-id" id="search-user-id"
             type="text" title="ID"/>
      <!-- USED FOR BETWEEN -->
      <input class="number int search-form-widget" value=""
             name="search-user-id-x" id="search-user-id-x"
             type="text" title="ID" style="display: none;"/>
    </td>
  </tr>
  <tr>
    <td id="search-user-name-td-label" class="caption">
      <label id="search-user-name-label">Name</label>
    </td>
    <td id="search-user-name-td-operator" class="operator">
      <select id="search-user-name-operator"
              class="operator-select"
              onchange="Arta.searchOperator(this);">
        <option value="C">Contains</option>
        <option value="A">Contain All</option>
        <option value="O">Contain One</option>
        <option value="E">=</option>
      </select>
    </td>
    <td id="search-user-name-td" >
      <input maxlength="45" class="text search-form-widget"
             name="search-user-name" id="search-user-name"
             type="text" title="Name"/>
    </td>
  </tr>
  <tr>
    <td id="search-save-button-td-label" class="caption">
      <label id="search-save-button-label"></label>
    </td>
    <td id="search-save-button-td-operator" class="operator"></td>
    <td id="search-save-button-td" >
      <button onclick="searchUser();" name="search-search-button" type="button"
              id="search-search-button" class="search-form-widget">
        Search
      </button>
    </td>
    </tr>
</table>

Bind search to model query data

Search forms require arta.js to be loaded to work.

JavaScript Arta.searchPack creates a search data pack which should be posted to the server. In below example the search pack is send by AJAX to the server:

function searchUser() {
    /* #search is id of the form container */
    var searchDataPack = Arta.searchPack('#search');
    /* URL of the factory to proccess the search on model */
    Arta.ajax('http://app.com/search-factory', searchDataPack);
}

On the server side method bind digests posted data, creates a query and injects is into the model object:

$user = new User();
$form = new FormSearch(/* form name */);

/* other conditions can be added to model beside the search */

/* bind search data pack from $_POST to model */
$form->bind($user);

/* bind (if a token match id found) then query model */
if ($form->bind($user, 'post')) {
    $user->query();
    /* FETCH DATA ... */
}

To get the search SQL statement instead of injecting it into the model object:

$user = new User();
$form = new FormSearch();

/* use search data pack from $_POST and return SQL statment for it */
$sql = $form->sql($user);

Cross-site request forgery

To help preventing cross-site request forgery when a form is rendered a random token is added to a hidden input and put inside the session. All binding methods: Form.bind(), Form::b() and Bind::pull() can check if posted form data comes with a valid token or not, if not they will return false without binding any data.

The third argument of this three methods is an optional boolean value or a parameter array. true means check token, if a parameter array is passed then array('token' => true) means check token. false and array('token' => false) will turn of token checking.

Methods Form.bind() and Form::b() will check tokens unless the third argument is set to prevent token checking. But Bind::pull() does not check tokens by default because class Binder is a generic class for binding model data to other data sources and not only form data.

Download example

Models - search form
TOP