PHP Forms

Table of contents

  1. Usage
  2. Layout
  3. CSRF
  4. HTTP Methods (REST verbs)
  5. Persistent values
  6. Supported controls
  7. Nested data/"forms"

Usage

composer require nitroxy/php-forms or install manually.

Simple form

Forms can be created using three different constructors: create, fromArray and fromObject. Among the three create is the simplest and most manual, only taking an ID and a closure.

Form::create('example1', function($f){
	$f->textField('name', 'My field name');
});
<form id="example1" class="form table" method="POST" action="">
	<table class="layout">
		<tr >
			<th class="form-label"><label for="example1_name">My field name</label></th>
			<td class="form-field"><input id="example1_name" name="name" type="text" /></td>
			<td class="form-hint" ></td>
			<td class="form-error"></td>
		</tr>
	</table>
</form>

Layout

PHP-Forms supports a few default layout engines or you can create your own custom. The layout engines is used to render each field.

Form::create("example2-$layout", function($f){
	$f->textField('name', 'My field name');
}, ['layout' => $layout]);

Tables (default)

The default layout is table-based and will put the labels and fields in columns. Quick-and-dirty way to get a form.

Plain

Plain layout is similar to tables but will instead use spans and divs.

My field name

Bootstrap

Outputs fields with bootstrap classes.

Unbuffered

A special layout called unbuffered also exists which allow full freedoom when creating the form. All fields is outputted directly as is, no labels, hints etc. Useful when you want to create a very custom form but still wants features such as value persistance, CRSF-protection, etc.

CSRF

To enable CSRF protection you need to extend Form. This will ensure the token is present on all forms (using a special hidden called csrf_token). The developer must validate the token when POSTing the form.

class MyForm extends Form {
	protected static function csrfToken(){
		return get_current_csrf_token();
	}
};
 
MyForm::create("example_csrf", function($f){
	/* ... */
});
<form id="example_csrf" class="form table" method="POST" action="">
	<input value="my-current-csrf-token" name="csrf_token" type="hidden" />
</form>

HTTP Methods (REST verbs)

To support other methods than GET and POST Form inserts a hidden field _method and uses POST to submit.

Form::create("example_method", function($f){
	/* ... */
}, ['method' => 'patch']);
<form id="example_method" class="form table" method="POST" action="">
	<input value="PATCH" name="_method" type="hidden" />
</form>
MethodSubmitted as_method
GETGETunset
POSTPOSTunset
PATCHPOSTPATCH
DELETEPOSTDELETE
... and so on.

Persistent values

By utilizing either fromArray or fromObject values can be stored and automatically filled into the form.

Objects will use the classname by default (e.g. MyCustomClass in the example) and fromArray has an argument for ID. In addition there is also an form option prefix which can be used to customize it. Field names are set as prefix[fieldname]. The major reason is to read the entire object at once by accessing $_POST['prefix'].

If you are using BasicObject you can use $model = MyModel::update_attributes($_POST['MyCustomClass'], ['permit' => ['name', 'age', role', description']); to update the model.

class MyCustomClass extends stdClass {
 
};
 
$myObject = new MyCustomClass;
$myObject->name = 'John Doe';
$myObject->age = 46;
$myObject->role = 2; /* frobnicator */
$myObject->description = 'Lorem ipsum dot sit amet.';
 
Form::fromObject($myObject, function($f){
	$f->textField('name', 'Name');
	$f->textField('age', 'Age', ['type' => 'number', 'min' => 1]);
	$f->select('role', 'Role', FormOptions::fromArray(['', 'Manager', 'Frobnicator', 'Developer']));
	$f->textarea('description', 'Description');
}, ['layout' => 'bootstrap']);

Nested data/"forms"

Forms can be nested by using fieldsFor to allow either sending to unrelated objects or multiple instances of the same class.

class MyClassA {};
class MyClassB {};
 
$a = new MyClassA; $a->name = 'Name A';
$b = new MyClassB; $b->name = 'Name B';
 
Form::create('example6', function($f) use ($a, $b) {
	$f->fieldsFor('A', $a, function($f){
		$f->textField('name', 'Name');
	});
	$f->fieldsFor('B', $b, function($f){
		$f->textField('name', 'Name');
	});
}, ['layout' => 'bootstrap']);
Fork me on GitHub