This package is developed for easing up the creation, validation & maintenance of web forms. The HTML forms can be generated directly from Mysql Tables, Eloquent ORM Models, using PHP code as well as from predefined XML format, if required the Loader can also be extended to support more type of obje

v2.1.1 2016-07-20 17:01 UTC

README

X2Form is a form generator/builder developed for easy creation & maintenance of web forms.

The X2Form architecture separates the definition of the form elements, rendering of the elements, positioning of the elements(layout/templates) and processing/validation of the form. This makes it very easy to update and maintain the forms in long term adding and removing more fields is extremely easy.

##Main features:

  1. It can create web forms from
  • Laravel/Eloquent models or objects.
  • mysql tables.
  • pure PHP calls by creating a X2Form\Form object and adding elements to it using the add* methods in Form class.
  • XML definition of the form.
  1. It can read values of dropdowns, checkboxes and radio from PHP functions, PHP Closures, PHP Global variables MYSQL queries.
  2. Supports HTML/PHP template for customizing the form layout
  3. Can handle file uploads, it can also rollback the file system changes if something goes wrong.
  4. It can do validation of the form values depending on the 'datatype' or 'datapattern'(using regular expressions)
  5. Values to be pre-populated in the form can be passed in as array
  6. Multi-Language support, you can define labels, tooltips, description as well as error messages in multiple languages. Thus making your form to render properly in multiple languages
  7. Easily extensible. Adding extra types of form elements or add more types of loaders, renderers and templates is easy.
  8. Clean name-spaced code
  9. Easy installation using Composer.

Installation & Configuration:

Using Composer Command

You can install X2Form on command line in your project using Composer by running

composer require sameer-shelavale/x2form

composer.json

Alternatively, you can add it directly in your composer.json file in require block

{
    "require": {
        "sameer-shelavale/x2form": "2.1.*"
    }
}

and then run composer update

PHP Include

You can also download the zip/rar archive and extract it and copy the folder to appropriate location in your project folder. And then include the autoload.php in your code

You also need to download MultiCaptcha and include it

include_once( 'PATH-TO-X2FORM-FOLDER/src/autoload.php' );
include_once( 'PATH-TO-MULTICAPTCHA-FOLDER/src/Captcha.php' );

Supported form controls/elements

X2Form supports following HTML controls:

  • text
  • textarea
  • checkbox
  • radio
  • dropdown
  • file
  • label
  • button ( i.e. <input type="button" > )
  • submit (i.e. <input type="submit" >)
  • reset (i.e. <input type="reset" > )
  • hidden (i.e. <input type="hidden" > )
  • image (i.e. <input type="image" > )
  • captcha

Usage

You can initialize an empty form just like

$form = new \X2Form\Form( 'MyFormName' );

MyFormName is the name of the form

$form = new \X2Form\Form(
    'MyFormName',
    [
        'action' => 'index.php',
        'method' => 'post'
    ]
);

Parameters

Form controls/elements

You can use constructor param named elements or after you initialize the form object you can use add* functions or the load method to load the elements from ORM objects or XML files or XML string or SimpleXML Object. First we will see the available element types and how to add them in the form.

text

This element creates a textbox or <input type="text"> control in the form

Basic parameters:

Advanced configuration parameters: Configuration attributes are mainly used for form validation or formatting the display

***IMP NOTE: besides all of the above basic and advanced params, all other normal HTML attributes for the <input type="text"> tag like style, class etc. can also be passed.

$form->addText([
    'name'=>'FIRST_NAME',
    'label'=>'First Name'
]);

textarea

This element creates a <textarea> control in the form

Basic parameters:

Advanced configuration parameters: Configuration attributes are mainly used for form validation or formatting the display

***IMP NOTE: besides all of the above basic and advanced params, all other normal HTML attributes for the <textarea> tag like style, class etc. can also be passed.

$form->addTextarea([
    'name'=>'INTRO',
    'label'=>'Write something about yourself',
    'rows'=>'5',
    'cols'=>'50',
    'value'=>'I am Harry... Harry Potter.'
]);

dropdown

This element creates a <select> control in the form

Basic parameters:

Advanced configuration parameters: Configuration attributes are mainly used for form validation or formatting the display

***IMP NOTE: besides all of the above basic and advanced params, all other normal HTML attributes for the <input type="dropdown"> tag like style, class etc. can also be passed.

basic example of dropdown is

$formObj->addDropdown([
    'name'=>'continent',
    'label'=>'Continent',
    'mandatory' => 'true',
    'options'=> [
        [ 'value'=>'africa', 'label'=>'Africa' ],
        [ 'value'=>'america', 'label'=>'America' ],
        [ 'value'=>'asia', 'label'=>'Asia' ],
        [ 'value'=>'australia', 'label'=>'Australia' ],
        [ 'value'=>'europe', 'label'=>'Europe' ],
    ]
);

Specifying the options

Firstly its very important to understand that each item in dropdown control is comprised of value and label (Same is true for radio and checkboxes types).

As said before, you can pass these groups of value-label pairs in multiple ways 1. php array here you can simply pass the labels and values as an array of strings. for example lets see this example, it uses a simple 1d array:

$formObj->addDropdown([
    'name'=>'continent',
    'label'=>'Continent',
    'options'=> ['array' => [ 'africa', 'america', 'asia', 'australia', 'europe' ] ],
);

When using 1d array each of the array element becomes the value and label as well. When values and labels are to be different you can use 2d array like:

$formObj->addDropdown([
    'name'=>'continent',
    'label'=>'Continent',
    'mandatory' => 'true',
    'options'=> [
        [ 'value'=>'afr', 'label'=>'Africa' ],
        [ 'value'=>'amr', 'label'=>'America' ],
        [ 'value'=>'asi', 'label'=>'Asia' ],
        [ 'value'=>'aus', 'label'=>'Australia' ],
        [ 'value'=>'eur', 'label'=>'Europe' ],
    ]
);

Now there may be cases where the keys of your array are not named value and label. In such situations you can tell it the name of valuefield and/or labelfield like.

//here is your 2d array where you don't have value and label keys
$customArray = [
    [ 'code'=>'afr', 'continent_name'=>'Africa' ],
    [ 'code'=>'amr', 'continent_name'=>'America' ],
    [ 'code'=>'asi', 'continent_name'=>'Asia' ],
    [ 'code'=>'aus', 'continent_name'=>'Australia' ],
    [ 'code'=>'eur', 'continent_name'=>'Europe' ]
];

$formObj->addDropdown([
    'name'=>'continent',
    'label'=>'Continent',
    'mandatory' => 'true',
    'options'=> [
        'array' => [
            'value' => $continentArray, // here we pass your array
            'labelfield' => 'continent_name', // we specify the label field
            'valuefield' => 'code', // we specify the value field
        ]
    ]
);

2. SQL queries: You can also load options from sql queries. All you need to do is just pass in the query to run, and the names of label and value fields. Ofcourse you should make sure you have the db connected and the dbHandle is set in your form object(for php & pdo). e.g. Assume that you have a mysql table named 'continents' like

now you can create options from this table as:

$formObj->addDropdown([
    'name'=>'continent',
    'label'=>'Continent',
    'mandatory' => 'true',
    'options' => [
        'query' => [
            'sql' => 'SELECT * FROM continents;', // here we pass the query
            'labelfield' => 'continent_name', // we specify the label field
            'valuefield' => 'code', // we specify the value field
        ]
    ]
);

alternatively you can also modify the query as select code as value, continent_name as label from continents; and you wont have to set the labelfield and valuefield.

3. php global variables You can also load the options from php global variables(or sub-elements of the element of the globals array) .e.g.

//somewhere in your code you set a global variable
$GLOBAL['location_data']['continents'] = [
    [ 'code'=>'afr', 'continent_name'=>'Africa' ],
    [ 'code'=>'amr', 'continent_name'=>'America' ],
    [ 'code'=>'asi', 'continent_name'=>'Asia' ],
    [ 'code'=>'aus', 'continent_name'=>'Australia' ],
    [ 'code'=>'eur', 'continent_name'=>'Europe' ]
];

$formObj->addDropdown([
    'name'=>'continent',
    'label'=>'Continent',
    'mandatory' => 'true',
    'options' => [
        'phpglobal' => [
            'var' => 'location_data:continents', // here we pass the continents array from location_data array in $GLOBALS vars
            'labelfield' => 'continent_name', // we specify the label field
            'valuefield' => 'code', // we specify the value field
        ]
    ]
);

4. anonymous functions: The anonymous functions are useful when defining the form in XML, you can process global variables/presets and create your data from it, like:

$continents = [
    [ 'code'=>'afr', 'continent_name'=>'Africa' ],
    [ 'code'=>'amr', 'continent_name'=>'America' ],
    [ 'code'=>'asi', 'continent_name'=>'Asia' ],
    [ 'code'=>'aus', 'continent_name'=>'Australia' ],
    [ 'code'=>'eur', 'continent_name'=>'Europe' ]
];

$formObj->addDropdown([
    'name'=>'continent',
    'label'=>'Continent',
    'mandatory' => 'true',
    'options' => [
        'create_function' => [
            'args' => '$a'
            'code' => 'foreach($a as $k => $val ){ $a[$k]["final_name"] = $a[$k]['continent_name']."(".$a[$k]['code'].")"; } return $a;', // the function code
            'pass'=> $continents, //we will pass $continents as argument $a to the function we will create
            'labelfield' => 'final_name', // we specify the label field
            'valuefield' => 'code', // we specify the value field
        ]
    ]
);

The above use of anonymous function and phpglobals looks very irrelevant in php definition but comes handy in XML where there is no immediate php processing available.

radio

This element creates a <input type="radio"> control in the form

Basic parameters:

Note: options for radio control can be passed exactly same way as the options for dropdown control as we have seen above.

Advanced configuration parameters: Configuration attributes are mainly used for form validation or formatting the display

***IMP NOTE: besides all of the above basic and advanced params, all other normal HTML attributes for the <input type="radio"> tag like style, class etc. can also be passed. basic example of radio is

$formObj->addRadio([
    'name'=>'gender',
    'label'=>'Gender',
    'mandatory' => 'true',
    'options'=> [
        [ 'value'=>'male', 'label'=>'Male' ],
        [ 'value'=>'female', 'label'=>'Female' ]
    ]
);

checkbox

This element creates a <input type="checkbox"> control in the form

Basic parameters:

Advanced configuration parameters: Configuration attributes are mainly used for form validation or formatting the display

***IMP NOTE: besides all of the above basic and advanced params, all other normal HTML attributes for the <input type="checkbox"> tag like style, class etc. can also be passed.

An example of checkbox with multiple options is:

$formObj->addRadio([
    'name'=>'hobbies',
    'label'=>'Select your hobbies',
    'direction' => 'vertical',
    'options'=> [
        [ 'value'=>'sports', 'label'=>'Sports' ],
        [ 'value'=>'music', 'label'=>'Listening music' ],
        [ 'value'=>'painting', 'label'=>'Drawing & Painting' ],
        [ 'value'=>'video-games', 'label'=>'Video Games' ]
    ]
);

An example of checkbox with single option is:

$formObj->addRadio([
    'name'=>'newsletter',
    'label'=>'Receive monthly newsletter?',
    'direction' => 'vertical',
    'options'=> [
        [ 'value'=>'yes', 'label'=>'Yes' ]
    ]
);

file

This element creates a <input type="file"> control in the form

Basic parameters:

Advanced configuration parameters: Configuration attributes are mainly used for form validation or formatting the display

***IMP NOTE: besides all of the above basic and advanced params, all other normal HTML attributes for the <input type="file"> tag like style, class etc. can also be passed.

hidden

This element creates a <input type="hidden"> in the form.

Basic parameters:

Advanced configuration parameters: Configuration attributes are mainly used for form validation or formatting the display.

$form->addHidden([
    'name'=>'product_id',
    'value'=> 3,
]);

label

This element creates a <label> in the form.

Basic parameters:

***IMP NOTE: besides all of the above params, all other normal HTML attributes for the <label> tag like style, class etc. can also be passed.

$form->addLabel([
    'name'=>'LABEL1',
    'value'=>'How many matches have you played?',
]);

button

This element creates a <input type="button"> in the form.

Basic parameters:

***IMP NOTE: besides all of the above params, all other normal HTML attributes for the <input type="button"> tag like style, class etc. can also be passed.

$form->addButton([
    'name'=>'button1',
    'value'=>'Calculate',
    'class' => 'btn btn-secondary' //these bootstrap classes are optional
]);

submit

This element creates a form submit button <input type="submit"> in the form.

Basic parameters:

***IMP NOTE: besides all of the above params, all other normal HTML attributes for the <input type="button"> tag like style, class etc. can also be passed.

$form->addSubmit([
    'name'=>'button2',
    'value'=>'Send',
]);

reset

This element creates a form reset button <input type="reset"> in the form.

Basic parameters:

***IMP NOTE: besides all of the above params, all other normal HTML attributes for the <input type="button"> tag like style, class etc. can also be passed.

$form->addReset([
    'name'=>'button3',
    'value'=>'Reset',
]);

image

This element creates a form reset button <input type="reset"> in the form.

Basic parameters:

***IMP NOTE: besides all of the above params, all other normal HTML attributes for the <input type="button"> tag like style, class etc. can also be passed.

$form->addReset([
    'name'=>'button3',
    'value'=>'Reset',
]);

captcha

This element inserts captcha in the form. By default this element uses an external package (Multi Captcha)[http://github.com/sameer-shelavale/multi-captcha] for rendering captcha.

Basic parameters:

***IMP NOTE: The label & description are automatically prepared for this field so you need not pass them, they will be ignored if you pass them.

$form->addCaptcha([
    'secret'=>'secret-code-for-this-form',
    'options'=> array(
        'math'=>[
            'level'=>4
        ],
        'gif' => [
            'maxCodeLength' => 6,
            'width'=>180,
            'height'=>60,
            'totalFrames'=>50,
            'delay'=>20
        ]
    ),
    'refreshUrl'=>'your-captcha-refresh-url.php?captcha=refresh',
    'helpUrl'=>'http://github.com/sameer-shelavale/multi-captcha'

]);

an example of form made with add* functions

$form = new \X2Form\Form(
    'ContactUs',
    [
        'action' => 'contact-us.php',
        'method' => 'post'
    ]
);
$form->addText([
    'name' => 'full_name',
    'label' => 'Your Name'
]);
$form->addText([
    'name' => 'email',
    'label' => 'Email',
    'mandatory' => true,
    'datatype' => 'email'
]);
$form->addTextarea([
    'name' => 'message',
    'label' => 'Message',
    'mandatory' => true
]);
$form->addRadio([
    'name' => 'gender',
    'label' => 'Gender',
    'options' => [ 'Male', 'Female' ]
]);
$form->addCaptcha([
    'name' => 'captcha',
    'secret'=>'contact-us-form-secret-blahblah',
    'options' => [
        'gif' => [
            'maxCodeLength' => 6,
            'width'=>200,
            'height'=>80
        ]
     ]
]);
$form->addSubmit([
    'name' => 'submit',
    'value' => 'Send'
];
$form->finalize(); //prepares the form for rendering, processing, validation etc.

specifying elements together in form constructor

We can also club the elements together in the form constructor param elements. Lets see how to do it for a simple contact us form.

$form = new \X2Form\Form(
    'ContactUs',
    [
        'action' => 'contact-us.php',
        'method' => 'post'
        'elements' => [
            [
                'type' => 'text',
                'name' => 'full_name',
                'label' => 'Your Name'
            ],
            [
                'type' => 'text',
                'name' => 'email',
                'label' => 'Email',
                'mandatory' => true,
                'datatype' => 'email'
            ],
            [
                'type' => 'textarea',
                'name' => 'message',
                'label' => 'Message',
                'mandatory' => true
            ],
            [
                'type' => 'radio',
                'name' => 'gender',
                'label' => 'Gender',
                'options' => [ 'Male', 'Female' ]
            ],
            [
                'type' => 'captcha',
                'name' => 'captcha',
                'secret'=>'contact-us-form-secret-blahblah',
                'options' => [
                    'gif' => [
                        'maxCodeLength' => 6,
                        'width'=>200,
                        'height'=>80
                    ]
                 ]
            ],
            [
                'type' => 'submit',
                'name' => 'submit',
                'value' => 'Send'
            ],
        ]
    ]
);
$form->finalize(); //prepares the form for rendering, processing, validation etc.

Note: It is necessary to run the finalize() function after you are done with adding/updating the form fields.

Rendering the form.

Once you finalize the form, everything else is very easy. To display the form all you need to do is

echo $form->render();

Remember that the render() function returns string, so you need to echo it.

processing & validating the form

After you finalize the form, you can process submission or validate it.

There is slight difference between the processSubmission() and validate() functions. The validate() function only validates the data and return boolean value as result and does nothing else, while the processSubmission() function validates the data as well as handles the file uploads also,i.e. it also moves the uploaded files to their target directories. It returns a detailed array log with status, message and array of error fields and their respective error messages.

    if( $_POST['submit'] == "Submit" ){
        if( logg_ok( $form->processSubmission( $_POST ) ){
            echo "Your data is submitted successfully!";
        }else{
            //display form again with submitted data populated in it and highlighted error fields
            echo '<span class="error">'.$form->errorString.'</span>';
            echo $form->render();
        }
    }else{
        //display form
        echo $form->render();
    }
    if( $_POST['submit'] == "Submit" ){
        if( $form->validate( $_POST ) ){
            //do extra/special validations and server side processing and save data etc.
        }else{
            //display form again with submitted data populated in it and highlighted error fields
            echo '<span class="error">'.$form->errorString.'</span>';
            echo $form->render();
        }
    }else{
        //display form
        echo $form->render();
    }

function processSubmission()

'function processSubmission( $postedData, $oldData, $cancelUploadsOnError = true )'

Almost all of the processing of form submission can be done with this one function.

Parameters:

$postedData - it is the posted data as associative array, where array keys are the name of fields, so most of the times you will be passing $_POST as $postedData

$oldData - You will need to pass this while editing existing records or data. It is mainly used for file handling and form validation. For example. if you have a form field PROFILE_PHOTO which is a mandatory field. Now even if the user don't upload new file for PROFILE_PHOTO, it should not throw error if the photo is uploaded previously. X2Form checks if the file is uploaded/exists in $oldData, if it exists it will not throw validation error.

$cancelUploadsOnError - this parameter states whether the uploaded files should be deleted on error or not. Certainly there will be cases where you are uploading multiple files and one of the upload fails due to problem in upload or moving or validation. In such cases we may need to rollback the changes in file system. If value of this parameter is true then X2Forms rolls back the changes in file system gracefully. Note. X2Forms backs up all the changes it is making in file-system, it creates backup files which it uses later for rollback.

Return Value - returns an array of result, code, message, errorFields result - it indicates whether the operation was a Success or Failure. so the value is either 'Success' or 'Failure' code - it is a short errorcode message - Description of the result of operation. you can generally display it to user as well. errorFields - Associative array of fields which did not pass validation, where array keys are the name of fields.

function validate()

'function validate( $postedData, $oldData)'

This function is used internally by the processSubmission() function.

Parameters:

$postedData - it is the posted data as associative array, where array keys are the name of fields, so most of the times you will be passing $_POST as $postedData

$oldData - You will need to pass this while editing existing records or data. It is mainly used for file handling and form validation. For example. if you have a form field PROFILE_PHOTO which is a mandatory field. Now even if the user don't upload new file for PROFILE_PHOTO, it should not throw error if the photo is uploaded previously. X2Form checks if the file is uploaded/exists in $oldData, if it exists it will not throw validation error.

Return Value - returns (boolean) true on successful validation or false

Note: Whatever $postedData you pass to the processSubmission() and validate() functions, it will be populated in the form. Also the functions mark fields with errors by setting the errorString property on that field(element) and these fields will have an extra css class errorfield. It also sets the '$form->errorString' which contains summery of the errors occurred during validation.

Refreshing elements using ajax

Rendering the form & form element using frameworks like bootstrap

By default X2Form renders form in tabular format, means using the <table> <tr> and <td> tags. You can also render it using bootstrap by setting the renderer to a bootstrap renderer object, yes that is all you need. for example:

$form = new \X2Form\Form(
    'MyFormName',
    [
        'action' => 'index.php',
        'method' => 'post',
        'renderer' => new X2Form\Renderers\Bootstrap\Renderer() //this is all you need to render in bootstrap
    ]
);

Note: Right now it supports table & bootstrap renderers only; we are planning to add jqueryui and angular renderers in future. You are however free to extend the current renderers or implement your own. Remember renderer MUST implement X2Form\Interfaces\Renderer interface.

Customising the form layout and positioning of elements using templates

There are times when you don't want the default two column vertical layout of the form and you want more control on positioning of the individual fields in the form. Even the buttons come up one below another.(May be I should add a button-group type in future)

In such situations the templates come really handy, using templates you can organize the form and position the elements as you want.

A X2Form template is a normal html/php file, all the data within the <body> and </body> tags is used as form template, the html <head> part is discarded, this is allows you to use any html editor to quickly make the template.

To place a Form Element in the template, just write text [ELEMENTNAME] in that place, here ELEMENTNAME is the name of Element.

After rendering the [ELEMENTNAME] will be replaced by actual html for the element.

So, for FIRST_NAME in, we can put in [FIRST_NAME]

Similarly, to place the label for element , put in [FIRST_NAME_label] notice the suffix _label here and to show the description use [FIRST_NAME_description].

While doing all this remember that you MUST NOT specify the <FORM> tag in the template the renderer places <form> tag around the template data automatically.

*Special thanks to JetBrains(http://www.jetbrains.com) for granting free license of jetBrains PHPStorm IDE for this project and their relentless support to the open-source community.