Skip to content
Syone edited this page Aug 6, 2023 · 6 revisions

Form

Form component helps you to build HTML forms.

Sy\Component\Html\Form is an abstract class derived from Sy\Component\Html\Form\FieldContainer

Form diagram

Create a form

You have to create a custom class derived from Sy\Component\Html\Form class. Your form class must define 2 methods:

  • init: setup your form in this method
  • submitAction: if you don't specify the form action attribute, form submission will call this method

For example:

<?php
use Sy\Component\Html\Form;

class ContactForm extends Form {

	public function init() {
		// Form configuration here...
	}

	public function submitAction() {
		// Form action here...
	}

}

Display the form:

<?php

$contactForm = new ContactForm();

echo $contactForm;

Output result:

<form action="" method="post">
<input name="sy-form-action-trigger" value="3b9a3791880252dccc23d0973c390c8a" type="hidden" />
</form>

Notice that when no action attribute is specified, $_SERVER['REQUEST_URI'] variable is used as action URI and a hidden input is generated in order to catch the submission event.

Set form attributes

You can use setAttribute or setAttributes method:

<?php
use Sy\Component\Html\Form;

class ContactForm extends Form {

	public function init() {
		// Set form attributes individually
		$this->setAttribute('id'     , 'contact_form');
		$this->setAttribute('class'  , 'contactForm');
		$this->setAttribute('method' , 'post');
		$this->setAttribute('action' , 'my_action.php');
		$this->setAttribute('enctype', 'multipart/form-data');

		// Or set multiple attributes at the same time
		$this->setAttributes([
			'id'      => 'contact_form',
			'class'   => 'contactForm',
			'method'  => 'post',
			'action'  => 'my_action.php',
			'enctype' => 'multipart/form-data',
		]);
	}

	public function submitAction() {
		// Submit action here...
	}

}

Output result:

<form id="contact_form" class="contactForm" method="post" action="my_action.php" enctype="multipart/form-data">
<input name="sy-form-action-trigger" value="3b9a3791880252dccc23d0973c390c8a" type="hidden" />
</form>

Set form options

<?php
use Sy\Component\Html\Form;

class ContactForm extends Form {

	public function init() {
		// Set form attributes individually
		$this->setOption('error-class'  , 'alert-error');
		$this->setOption('success-class', 'alert-success');

		// Or set multiple options at the same time
		$this->setOptions(array(
			'error-class'   => 'alert-error',
			'success-class' => 'alert-success',
		));
	}

	public function submitAction() {
		// Submit action here...
	}

}

Option keys available

Key Value type Value description
'error' string Error message
'success' string Success message
'error-class' string Error div class
'success-class' string Success div class

Add form elements

Form derives from FieldContainer. Methods available for adding elements in a form:

  • FieldContainer FieldContainer::addDiv([array $attributes = array()])
  • FieldContainer FieldContainer::addFieldset([string $label = NULL])
  • Element FieldContainer::addLabel(string $label [, array $attributes = array()])
  • Element FieldContainer::addButton(string $label [, array $attributes = array()])
  • Checkbox FieldContainer::addCheckbox([array $attributes = array() [, array $options = array()]])
  • CheckboxSet FieldContainer::addCheckboxSet([array $checkboxes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addColor([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addDate([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addMonth([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addWeek([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addTime([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addDateTime([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addDateTimeLocal([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addEmail([array $attributes = array() [, array $options = array()]])
  • File FieldContainer::addFile([array $attributes = array() [, array $options = array()]])
  • Hidden FieldContainer::addHidden([array $attributes = array() [, array $options = array()]])
  • Input FieldContainer::addImage([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addNumber([array $attributes = array() [, array $options = array()]])
  • TextInput FieldContainer::addPassword([array $attributes = array() [, array $options = array()]])
  • Radio FieldContainer::addRadio([array $attributes = array() [, array $options = array()]])
  • RadioSet FieldContainer::addRadioSet([array $radios = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addRange([array $attributes = array() [, array $options = array()]])
  • Input FieldContainer::addReset([array $attributes = array() [, array $options = array()]])
  • OptionContainer FieldContainer::addSelect([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addSearch([array $attributes = array() [, array $options = array()]])
  • Input FieldContainer::addSubmit([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addTel([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addTextInput([array $attributes = array() [, array $options = array()]])
  • Textarea FieldContainer::addTextarea([array $attributes = array() [, array $options = array()]])
  • TextFillableInput FieldContainer::addUrl([array $attributes = array() [, array $options = array()]])

Most of these methods take 2 optionnal associative arrays in argument. An attributes array and an options array.
In the attributes array you can put all html attributes for an element : id, name, class etc...
In the options array you can have some extra attributes, in general : label, required, validator etc...

And all of these methods will return the added element object.

For example:

<?php
use Sy\Component\Html\Form;

class ContactForm extends Form {

	public function init() {
		// Form attributes
		$this->setAttribute('id', 'cform');
		$this->setAttribute('name', 'contact_form');

		// Add a text input
		$this->addTextInput(
			array(
				'id'   => 'fname',
				'name' => 'firstname'
			),
			array(
				'label'    => 'Firstname',
				'required' => true
			)
		);

		// Add a text input in another way
		$lastname = $this->addTextInput();
		$lastname->setAttributes(array(
			'id'   => 'lname',
			'name' => 'lastname',
		));
		$lastname->setOptions(array(
			'label'    => 'Lastname',
			'required' => true,
		));

		// Add a text input with email validator
		$this->addTextInput(
			array(
				'id'   => 'mail',
				'name' => 'email'
			),
			array(
				'label'     => 'E-mail',
				'required'  => true,
				'validator' => array('email'),
			)
		);

		// Add a textarea
		$message = $this->addTextarea();
		$message->setAttribute('name', 'message');
		$message->setOption('label', 'Message');
		$message->setOption('required', true);

		// Add a submit button
		$this->addSubmit(array('value' => 'Send'));
	}

	public function submitAction() {
		// Form action here...
	}

}

Output result:

<form id="cform" name="contact_form" action="" method="post">
<input name="sy-form-action-trigger" value="3b9a3791880252dccc23d0973c390c8a" type="hidden" />
<label for="fname">Firstname</label>
<input id="fname" name="firstname" type="text" />

<label for="lname">Lastname</label>
<input id="lname" name="lastname" type="text" />

<label for="mail">E-mail</label>
<input id="mail" name="email" type="text" />

<label>Message</label>
<textarea name="message"></textarea>

<input value="Send" type="submit" />
</form>

Check if a form is valid

After a form submission, you can use isValid method to check if all elements in the form is valid.
If you want to fill the form, you can use fill method.

Data must be provided to these method, you can use $_POST or $_GET or any other data source.

A form can have an error/success message that will be shown after the form validation. And each element can also have an error message.

<?php
use Sy\Component\Html\Form;

class ContactForm extends Form {

	public function init() {
		// Form configuration here...

		// Set error message in a form element
		$this->addTextInput(
			array(
				'id'   => 'fname',
				'name' => 'firstname'
			),
			array(
				'label'    => 'Firstname',
				'required' => true,
				'error'    => 'This field is required',
			)
		);
	}

	public function submitAction() {
		if ($this->isValid($_POST)) {
			// success !

			// Set success message
			$this->setOption('success', 'Message sent successfully');
			// Or use the shortcut
			$this->setSuccess('Message sent successfully');
		} else {
			// failure !

			// Set error message
			$this->setOption('error', 'Please fill the form correctly');
			// Or use the shortcut
			$this->setError('Please fill the form correctly');

			// Fill the form
			$this->fill($_POST);
		}
	}

}

Html ouput result if the validation failed

<form action="/example_form.php" method="post">
<div class="error">Please fill the form correctly</div>
<input name="sy-form-action-trigger" value="form-1" type="hidden" />
<label for="fname">Firstname</label>
<span class="error">This field is required</span>
<input id="fname" name="firstname" value="" type="text" />
</form>

The form error message will be placed in a div with css class named error.
Error message of each form element will be placed in a span with class named error.

Validator function

There is a list of validators defined:

  • boolean
  • email
  • float
  • int
  • ip
  • url

You can use your own validation function. A validator function must take one parameter and must return a boolean.

<?php
use Sy\Component\Html\Form;

// Define your custom validator function
function validate_me($value) {
	return true;
}

class ContactForm extends Form {

	// Define your custom validator method
	private function test($value) {
		return $value != 'test';
	}

	public function init() {
		// Form configuration here...

		// Use predefined validator
		$text = $this->addTextInput();
		$text->addValidator('Sy\Component\Html\Form\email');

		// Use your custom validator
		$text = $this->addTextInput();
		$text->addValidator('validate_me'); // function callback
		$text->addValidator(array($this, 'test')); // method callback
	}

	public function submitAction() {
		// Form action here...
	}

}

Notice that validator option is an array, you can put several validator for one element.

Form design

Use CSS for form design

You can use your own CSS and combine it with fieldset or div container to help you to design your form.

For example:

<?php
use Sy\Component\Html\Form;

class ContactForm extends Form {

	public function init() {

		// Use a style sheet
		$this->addCssLink('/path/to/your/sheet/style.css');

		// Form attributes
		$this->setAttribute('id', 'cform');
		$this->setAttribute('name', 'contact_form');

		// Add a fieldset with legend
		$fieldset = $this->addFieldset('Contact Form');

		// Add a text input into a div
		$fieldset->addDiv()->addTextInput(
			array(
				'id'    => 'fname',
				'name'  => 'firstname',
			),
			array(
				'label'    => 'Firstname',
				'required' => true,
				'error'    => 'This field is required',
			)
		);

		// Add a text input into a div in another way
		$lastname = $fieldset->addDiv()->addTextIput();
		$lastname->setAttributes(array(
			'id'    => 'lname',
			'name'  => 'lastname',
		));
		$lastname->setOptions(array(
			'label'    => 'Lastname',
			'required' => true,
			'error'    => 'This field is required',
		));

		// Add a text input into a div with email validator
		$fieldset->addDiv()->addTextInput(
			array(
				'id'    => 'mail',
				'name'  => 'email',
			),
			array(
				'label'     => 'E-mail',
				'required'  => true,
				'validator' => array('email'),
				'error'     => 'This must be a valid email address',
			)
		);

		// Add a textarea
		$message = $fieldset->addDiv()->addTextarea();
		$message->setAttribute('name', 'message');
		$message->setOption('label', 'Message');
		$message->setOption('required', true);
		$message->setOption('error', 'Please write a message');

		// Add a submit button
		$fieldset->addDiv(array('class' => 'button'))->addSubmit(array('value' => 'Send'));

	}

	public function submitAction() {
		if ($this->isValid($_POST)) {
			// success !
			$this->setSuccess('Message sent successfully');
		} else {
			// failure !
			$this->setError('Please fill the form correctly');

			// Fill the form
			$this->fill($_POST);
		}
	}

}

Output result:

<form action="/example_form.php" method="post" id="cform" name="contact_form">
<input name="sy-form-action-trigger" value="form-1" type="hidden" />
<fieldset>
<legend>Contact Form</legend>
<div>
<label for="fname">Firstname</label>
<input id="fname" name="firstname" type="text" />
</div>
<div>
<label for="lname">Lastname</label>
<input id="lname" name="lastname" type="text" />
</div>
<div>
<label for="mail">E-mail</label>
<input id="mail" name="email" type="text" />
</div>
<div>
<label>Message</label>
<textarea name="message"></textarea>
</div>
<div class="button">
<input value="Send" type="submit" />
</div>
</fieldset>
</form>

Apply your CSS, style.css

#cform {
	width: 400px;
	font-family: Arial,Helvetica,sans-serif;
	font-size: 12px;
}

#cform .error {
	color: red;
	text-transform: uppercase;
}

#cform .success {
	color: green;
}

#cform label {
	display: block;
	font-weight: bold;
}

#cform span.error {
	display: block;
}

#cform textarea {
	width: 100%;
	height: 50px;
}

#cform .button {
	text-align: right;
}

Use custom template file

If you really need to make a complicated design, you can use a custom template file:

<?php
use Sy\Component\Html\Form;

class ContactForm extends Form {

	public function init() {

		// Use a style sheet
		$this->addCssLink('/path/to/your/sheet/style.css');

		// Use a custom template
		$this->setTemplateFile('/path/to/your/file/template.html');

	}

}

Render a form

You have several ways to use your form.

Display the form directly

<?php

// Create an instance of your form
$contactForm = new ContactForm();

// You can use render method
$contactForm->render();

// Or echo it !
echo $contactForm;

Use it on your own template file

<?php
require 'path/to/your/sy/install/directory/sy.inc.php';
require 'path/to/your/component/ContactForm.php';

// Create an instance of your form
$contactForm = new ContactForm();
?>
<html>
	<head>
		<title>Contact Form</title>
	</head>
	<body>
		<?php echo $contactForm ?>
	</body>
</html>

Use it on another component like Sy\Component\Html\Page

<?php
use Sy\Component\Html\Page;

$contactForm = new ContactForm();
$page = new Page();
$page->setBody($contactForm);
echo $page;

Use it on a custom component, for example on MyComponent.php

<?php

class MyComponent extends Sy\WebComponent {

	public function __construct() {
		parent::__construct();
		$this->setTemplateFile('MyTemplate.html');
		$this->setComponent('CONTACT_FORM', new ContactForm());
	}

}

Template file used by MyComponent: MyTemplate.html

<html>
	<head>
		<title>Contact Form</title>
	</head>
	<body>
		{CONTACT_FORM}
	</body>
</html>