Download the PHP package naucon/form without Composer
On this page you can find all versions of the php package naucon/form. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Package form
Short Description The Package provides a form component for php to process and validate html forms. A form helper is also included to render your form in html markup (php oder smarty templates).
License MIT
Homepage https://github.com/naucon/Form
Informations about the package form
naucon Form Package
About
The Package provides a form component for php to process and validate html forms. A form helper is also included to render your form in html markup (php oder smarty templates).
One of the most common tasks in a web developing are forms. This package helps you to process and validate forms in an easy way to maintain and secure.
The package can be integrated into any php web application (min. php5.5+).
Features
- Binding form data to an entity by getter and setter
- validate form data by validation rule defined in the entity
- secure forms with synchronizer token to prevent XSRF/CSRF vulnerabilities
- support form collections
- translate form labels and form violations
- form helper to render html markup
- rendering html forms with output filtering to prevent XSS vulnerabilities
- smarty plugins for form helper
Compatibility
- PHP 7.1 - 7.4
Installation
install the latest version via composer
composer require naucon/form
Examples
Start the build-in webserver to see the examples in action:
cd examples
php -S 127.0.0.1:3000
open url in browser
http://127.0.0.1:3000/index.html
Get Started
1. Entity
First we need an entity. The entity can be a plain php class with getter and setter. The attributes of the class have to be accessible through getters and setters or by being public. The submitted form data will be mapped to an instance of this entity.
3. XSRF/CSRF Protection
When bind()
is submitted the data will only be processed if a synchronizer token (also called secure token or xsrf/csrf token) was submitted and is valid. This token prevents XSRF/CSRF attacks by setting a random token to the session when a form is presented. In the form the token is added to a hidden field. When the form data are submitted the token is part of the payload and will be compared to the previously stored token in the session. The binding will only be processed if these two token are identical.
<form method="post">
<input type=text name="_csrf_token" value="" />
The markup looks like this:
<form method="post" id="yourform">
<input type="hidden" name="_csrf_token" value="67187c7e5abeb31b93339ab5cbb263b6" />
The XSRF/CSRF protection can be disabled when calling the method setSynchronizerTokenValidation()
with parameter false
.
$formManager->setSynchronizerTokenValidation(false);
or
$form->setSynchronizerTokenValidation(false);
4. Validation
To validate the submitted form data we use the Symfony Validator Component.
The constrains (validation rules) are defined in a static method loadValidatorMetadata()
, yml file, xml file or annotation within the entity.
How to define constrains and which validators are available, please have a look at the Symfony Validator documentation: https://symfony.com/doc/2.8/validation.html
In our example we add a static method loadValidatorMetadata()
to our User
entity:
public static function loadValidatorMetadata(ClassMetadata $metadata)
{
$metadata->addPropertyConstraint('username', new Assert\NotBlank());
$metadata->addPropertyConstraint('username', new Assert\Length(
array('min' => 5, 'max' => 50)
));
$metadata->addPropertyConstraint('email', new Assert\Email());
$metadata->addPropertyConstraint('age', new Assert\Type('numeric'));
}
You can also use yml, xml files or annotations. For more information how to define constrains, have a look at the Symfony Validator documentation: http://symfony.com/doc/current/components/validator.html
$options['config_paths'] = array(__DIR__ . '/Resources/config/');
$formManager = new FormManager($options);
In case you need to exclude certain validation constraints for a particular use case, or you would like to apply only a condition subset by configuration, you may use validation groups to do so:
$options['validation_groups'] = array('Default', 'registration');
If an array of validation group names is supplied in the form options, then only constraints marked with those group names will be applied when validating the form. To find out more about validation group configuration, please see the documentation at https://symfony.com/doc/current/validation/groups.html.
Next we call isValid()
after bind()
and isBound()
. In other words we validate the entity after it is bound.
$form->bind(isset($_POST) ? $_POST : null);
if ($form->isBound()
&& $form->isValid()) {
// some action, like saving the data to database
}
// here rendered the form html!
session_write_close();
?>
Validation errors stored in a FormError
instance. They can be accessed through the following methods:
$form->getErrors()
$entityContainer->hasError('username')
$entityContainer->getError('username')
$entityContainer->getError('username')->getMessage();
$entityContainer
is an instance of EntityContainer
. It is not the entity User
. The EntityContainer
contains the entity. It can be acceessed by calling EntityContainer::getEntity()
.
If your form contains only one entity - you can access the EntityContainer by calling:
$form->getFirstEntityContainer()
If your form contains multiple entities you can iterate through the EntityContainer:
foreach ($form->getEntityContainerIterator() as $entityContainer) {
...
}
Entity container can also be iterated through a form instance.
foreach ($form as $entityContainer) {
...
}
5. Translation
To translate form label and validation violations we use the symfony translator component.
To change the current language call setLocales
:
$form->getTranslator()->setLocale('de_DE');
You can specify the current and a fallback language in the configuration:
$options = [
'locale' => 'en_EN',
'fallback_locales' => array('en_EN'),
];
$formManager = new FormManager($options);
The default translations for the contrains from the form and symfony components are loaded by default. To add translations form labels or your own contrains you have to specify one ore more pathes where to find these translations:
$paths = array(realpath(__DIR__) . '/Resources/translations');
$options['translator_paths' => $paths];
$formManager = new FormManager($options);
6. Form rendering
With Form Helper
With the form helper you can easily render a html form field, labels, buttons without worrying about field names and values.
The following form helpers are available and can be accessed through the FormHelper
instance or smarty plugins.
- Choices
- "checkbox"
- "radio"
- "select"
- Fields
- "error"
- "hidden"
- "label"
- "password"
- "text"
- "textarea"
- Tags
- "errors"
- "reset"
- "submit"
Limitations: At the moment the form helper do not consider different html standards like html4.01, xhtml, html5 etc. Also some html markup notations are missing.
FormHelper with php templates
First you have to create an instance of the FormHelper
class. The form helper requires an instance of a Form
instance.
<fieldset>
<br/>
<br/>
<br/>
</fieldset>
<fieldset>
</fieldset>
" value="" />
<br/>
<label>First name</label>
<input type="text" name="" value="" />
<br/>
Form Collections
To process (bind and validate) more than one form you can use a form collection. A form collection can be created through calling createFormCollection()
from the FormManager
.
As first parameter add an array of entities. The second parameter is the form name. The entities must not have the same time - but in the following example we do.
$products = array(new Product(), new Product(), new Product());
use Naucon\Form\FormManager;
$formManager = new FormManager();
$form = $formManager->createFormCollection($products, 'yourforms');
$form->bind($_POST);
To render the form we iterate through the form entites like this:
foreach ($form->getEntityContainerIterator() as $entityContainer) {
The behaviour of a form collection can be specified with the collection_type
option. The value can be one of these options FormCollectionInterface::COLLECTION_TYPE_ALL, FormCollectionInterface::COLLECTION_TYPE_MANY, FormCollectionInterface::COLLECTION_TYPE_ONE.
FormCollectionInterface::COLLECTION_TYPE_ALL
: payload must bind all form entitiesFormCollectionInterface::COLLECTION_TYPE_ANY
: payload can bind any matching form entitiesFormCollectionInterface::COLLECTION_TYPE_ONE
: payload must bind one defined form entity. Which one is defined through the form option.FormCollectionInterface::COLLECTION_TYPE_MANY
: payload must bind one or more form entities. Which ones are defined through form options.
Collection type one
For example you have two forms with a different set of fields where the use have to choose from. We would use the COLLECTION_TYPE_ONE or COLLECTION_TYPE_MANY. Add a third parameter with the collection type.
$creditCardEntity = new CreditCard();
$directDebitEntity = new DirectDebit();
$paymentMethods = array('cc' => $creditCardEntity, 'dd' => $directDebitEntity);
use Naucon\Form\FormManager;
use Naucon\Form\FormCollectionInterface;
$formManager = new FormManager();
$forms = $formManager->createFormCollection($paymentMethods, 'payment_forms', FormCollectionInterface::COLLECTION_TYPE_ONE);
$forms->bind($_POST);
For every form entity we add a radio button or checkbox like this:
foreach ($forms->getEntityContainerIterator() as $entityContainer) {
if ($entityContainer->getName()=='cc') {
?>
<fieldset>
<input type="radio" name="" value="" />
<label>Credit Card</label>
<br/>
</fieldet>
with helpers it would look like this:
$formHelper = new FormHelper($form);
echo $formHelper->formStart();
echo $formHelper->formTag('errors');
foreach ($formHelper as $formEntity) {
if ($formEntity->getName()=='cc') {
?>
<fieldset>
in smarty it would look like this:
{ncform from=$form}
{ncform_tag type='errors'}
{foreach from=$formHelper item="formEntity"}
{if $formEntity->getName()=='cc'}
<fieldset>
{ncform_option type='radio' choice='cc'}
To define a default form option call FormCollection::setFormOptionDefaultValues(array $defaultValues)
or FormCollection::addFormOptionDefaultValues($formEntityName)
.
$forms->setFormOptionDefaultValues(array('cc'))
or
$forms->addFormOptionDefaultValues('dd');
Configuration
The forms can be configured by adding a parameter when creating a form manager or form instance.
$formManager = new FormManager($options);
or
$form = $formManager->createForm($entity, 'testform', $options);
The default options look like this:
$options = [
'csrf_parameter' => '_csrf_token',
'csrf_protection' => true,
'collection_type' => FormCollectionInterface::COLLECTION_TYPE_ALL,
'locale' => 'en_EN',
'fallback_locales' => array('en_EN'),
'translator_paths' => array(),
'config_paths' => array()
];
csrf_parameter
= specifies the name attribute of csrf input hidden fieldcsrf_protection
= enabled/disables csrf protectioncollection_type
= see documentation for form collectionlocale
= default languagefallback_locales
= fallback language if a translation is not find in the current languagetranslator_paths
= specifies where the translation files are locatedconfig_paths
= specifies where the validation files are located
Form Hooks
With hooks in the form entity you can influence the form processing. In the following example we use prevalidation hook to remove whitespaces from the already bind properties. Also we add additional validation to a post validation hook.
class Address
{
protected $streetName;
protected $streetNumber;
protected $postalCode;
protected $town;
protected $country;
...
public function prevalidatorHook(FormHook $formHook)
{
$this->streetName = trim($this->streetName);
$this->streetNumber = trim($this->streetNumber);
$this->postalCode = trim($this->postalCode);
$this->town = trim($this->town);
$this->country = trim($this->country);
}
public function postvalidatorHook(FormHook $formHook)
{
if ($this->postalCode != '54321') {
$formHook->setError('postal_code', 'has unexpected value');
}
}
...
The hook is basically a method with a defined naming conversion within the form entity. If present in a form entity it will be called while processing.
- postbindHook (called after a entity is bound)
- prevalidatorHook (called befor a entity is validated)
- postvalidatorHook (called after a entity was validated)
The hooks receives an instance of FormHook
which gives you restricted access to entity container to change errors:
- getErrors()
- hasErrors()
- getError($key)
- hasError($key)
- setError($key, $message)
Roadmap
- decouple translation, validator from configuration (smaller, extra options)
- test label mit alpha entity names / collections
- test encoding value
- rename form error to violation
- violation for form collection option (inkl. translation)
- violation for csrf validation (inkl. translation)
- state machine for bind and validation
- add smarty block plugin to restrict form output to first or last entity (for tables and buttons).
- add smarty block plugin to restrict to defined entity (form collections).
All versions of form with dependencies
psr/log Version ~1.0
doctrine/annotations Version ^1.0
doctrine/cache Version ^1.0
naucon/utility Version ~1.0
naucon/htmlbuilder Version ~1.0
symfony/validator Version ^6.0
symfony/property-access Version ^6.0
symfony/security-csrf Version ^6.0
symfony/event-dispatcher Version ^6.0
symfony/finder Version ^6.0
symfony/options-resolver Version ^6.0
symfony/translation Version ^6.0
symfony/yaml Version ^6.0
symfony/cache Version ^6.0