dev-master
9999999-devForm Builder
MIT
The Requires
- php >=5.4
- zendframework/zend-escaper 2.3.*
The Development Requires
form forms
Wallogit.com
2017 © Pedro Peláez
Form Builder
A light-weight, template-oriented form builder., (*2)
Use composer to install package formular/formular., (*3)
Consider the following:, (*4)
// ./templates/input.phtml
<div class="row">
<input <?= $this->type->attr('text'); ?> <?= $this->attr(['id', 'name', 'value', 'placeholder']); ?>>
</div>
// ./templates/submit.phtml
<div class="row">
<button type="submit"><?= $this->label; ?></button>
</div>
// ./src/form.php
use bigwhoop\Formular\Form;
use bigwhoop\Formular\TemplateFactory\FileBasedFactory;
$templateFactory = new FileBasedFactory();
$templateFactory->addTemplatesPath(__DIR__ . '/../templates');
$form = new Form();
$form->setTemplatesFactory($templateFactory);
$form->addElement('input', ['id,name' => 'name', 'placeholder' => 'Your name']);
$form->addElement('input', ['id,name,type' => 'email', 'placeholder' => 'Your email address']);
$form->addElement('submit', ['label' => 'Register']);
echo $form->render();
This will output ..., (*5)
<div class="row">
<input type="text" id="name" name="name" placeholder="Your name">
</div>
<div class="row">
<input type="email" id="email" name="email" placeholder="Your email address">
</div>
<div class="row">
<button type="submit">Register</button>
</div>
So what is happening here?, (*6)
First we create some .phtml files in a directory. This templates directory we then register with the form using a new
FileBasedFactory. The name of the files minus the extension are used as the template's name. Next we define some
elements using the available templates. When rendering the specified element, its attributes will get passed on to the
templates., (*7)
Here are the conventions you need to know., (*8)
Templates are provided by template factories. The easiest factory is a the file-based FileBasedFactory; as seen
in the first example. There templates are .phtml files laying around in directories. You can add as many such
directories to your form as you wish., (*9)
Let's have a look at the following example:, (*10)
// ./templates1/input.phtml
// ./templates2/input.phtml
...
$templateFactory->addTemplatesPath('./templates1');
$templateFactory->addTemplatesPath('./templates2');
...
$form->addElement('input');
$form->render();
This will make Formular go BOOM becaue it doesn't know which input template to use. To solve this problem you can use
namespaces., (*11)
$templateFactory->addTemplatesPath('./templates1');
$templateFactory->addTemplatesPath('./templates2', 'foo');
...
$form->addElement('input'); // uses ./templates1/input
$form->addElement('input@foo'); // uses ./templates2/input
You can also define a default namespace., (*12)
$templateFactory->addTemplatesPath('./templates1', 'fu');
$templateFactory->addTemplatesPath('./templates2', 'foo');
$templateFactory->setDefaultNamespace('foo');
...
$form->addElement('input@fu'); // => uses ./templates1/input
$form->addElement('input'); // => uses ./templates2/input
$form->addElement('input@foo'); // => uses ./templates2/input
Inside templates you can access the element data/attributes using $this->[KEY]. This will provide access to a
Value object with a set of little helpers to make things easier. Even if the attribute does not exist you'll get
such an object. It's default value will be null., (*13)
// Returns a Value object representing attribute 'foo'.
<?php $foo = $this->foo; ?> # instance of \bigwhoop\Formular\Template\Value
// Prints an escaped string representing attribute 'foo'.
<?= $this->foo; ?> # '[SAFE_VALUE]' or '' if value is empty
<?= $this->foo->str(); ?> # '[SAFE_VALUE]' or '' if value is empty
<?= $this->foo->str('bar'); ?> # '[SAFE_VALUE]' or 'bar' if value is empty
// Returns the value the attribute encapsulates.
<?php $val = $this->foo->val(); ?> # [VALUE] or null if no value was set
<?php $val = $this->foo->val('bar'); ?> # [VALUE] or 'bar' if value is empty
// Prints a string in the format of '[KEY]="[VALUE]"'. Prints an empty string if the value is empty.
<?= $this->foo->attr(); ?> # 'foo="[SAFE_VALUE]"' or '' if value is empty
<?= $this->foo->attr('bar'); ?> # 'foo="[SAFE_VALUE]"' or 'foo="bar"' if value is empty
// Prints a string in the format of '[KEY]'. Prints an empty string if the value is empty.
<?= $this->foo->prop(); ?> # 'foo'/[KEY] or '' if value is empty
<?= $this->foo->prop(true); ?> # 'foo'/[KEY]
<?= $this->foo->prop(false); ?> # 'foo'/[KEY] or '' if value is empty
Inside templates you can also use some helper methods using $this->[HELPER]()., (*14)
// Pass the current element data to a different template
<?= $this->partial('template@ns'); ?>
// Render multiple attributes at once
<?= $this->attr(['id', 'name']); ?>
... same as ...
<?= $this->id->attr(); ?> <?= $this->name->attr(); ?>
// Render multiple properties at once
<?= $this->prop(['id', 'name']); ?>
... same as ...
<?= $this->id->prop(); ?> <?= $this->name->prop(); ?>
The following forms/templates have been created so far:, (*15)
Other packages:, (*16)
Use the continue binding to define where the next template should be rendered. By default the next template is rendered and appended to the current template., (*17)
For ..., (*18)
<div class="depth-<?= $this->depth; ?>"></div>
...
$form->addElement('template', ['depth' => 1]);
$form->addElement('template', ['depth' => 2]);
... the output would be ..., (*19)
<div class="depth-1"></div> <div class="depth-2"></div>
If you use the continue binding, ..., (*20)
<div class="depth-<?= $this->depth; ?>">
<?= $this->next->val(); ?>
</div>
...
$form->addElement('template', ['depth' => 1, 'next' => $form->bindContinue(); ]);
$form->addElement('template', ['depth' => 2, 'next' => $form->bindContinue(); ]);
$form->addElement('template', ['depth' => '3a']);
$form->addElement('template', ['depth' => '3b']);
... you get the following, nested output:, (*21)
<div class="depth-1>
<div class="depth-2">
<div class="depth-3a"></div>
<div class="depth-3b"></div>
</div>
</div>
**Make sure to call the val() and not str() on the bound value as otherwise you'd get escaped text., (*22)
The error messages binding allows for easy access to the error messages that occurred during validation. See the validation chapter for more information on how to set up validators., (*23)
<ul>
<?php foreach ((array)$this->errors->val() as $error): ?>
<li><?= $error; ?></li>
<?php endforeach; ?>
</ul>
...
$form->addElement('template', ['errors' => $form->bindErrorMessages()]);
Using the value binding you can pass a wrapped value into the template that gets unwrapped not until you access it., (*24)
<h1><?= $this->name; ?></h1>
...
$obj->setName('Tim');
$form->addElement('template', [
'name' => $form->bindValue([$obj, 'getName']),
]);
$obj->setName('John');
$form->render();
The output will be <h1>John</h1> and not <h1>Tim</h1>., (*25)
You can bind to all possible callables and even public object properties [$obj, 'propertyName']., (*26)
Using $form->bindVariable() it's also possible to bind to a variable., (*27)
$var = 'Tim';
$form->addElement('text', [
'name' => $form->bindVariable($var),
]);
$var = 'James';
$form->render(); // => <h1>James</h1>
The following adapters are available:, (*28)
\bigwhoop\Formular\Validation\Adapter\ZendFrameworkAdapter
\bigwhoop\Formular\Validation\Adapter\RespectValidationAdapter
See the validators example for how to use them., (*29)
WIP, (*30)
See LICENSE file., (*31)
Form Builder
MIT
form forms