
Resumen
Phalcon ofrece un componente bajo el espacio de nombres Phalcon\Forms
que ayuda a los desarrolladores a crear y mantener formularios que se pueden usar para renderizar elementos HTML en pantalla además de realizar validaciones sobre los datos introducidos en esos elementos.
<?php
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Element\Select;
$form = new Form();
$form->add(
new Text(
'nameLast'
)
);
$form->add(
new Text(
'nameFirst'
)
);
$form->add(
new Select(
'phoneType',
[
1 => 'Home',
2 => 'Work',
3 => 'Mobile',
]
)
);
En la plantilla:
<h1>
Contacts
</h1>
<form method='post'>
<p>
<label>
Last Name
</label>
<?php echo $form->render('nameLast'); ?>
</p>
<p>
<label>
First Name
</label>
<?php echo $form->render('nameFirst'); ?>
</p>
<p>
<label>
Gender
</label>
<?php echo $form->render('phoneType'); ?>
</p>
<p>
<input type='submit' value='Save' />
</p>
</form>
Cada elemento del formulario puede ser renderizado por el desarrollador como obligatorio. Internally, Phalcon\Tag is used to produce the correct HTML for each element, and you can pass additional HTML attributes as the second parameter of render()
:
<p>
<label>
Name
</label>
<?php
echo $form->render(
'nameFirst',
[
'maxlength' => 30,
'placeholder' => 'First Name',
]
); ?>
</p>
Los atributos HTML también se pueden definir en la definición del elemento:
<?php
use Phalcon\Forms\Form;
$form = new Form();
$form->add(
new Text(
'nameFirst',
[
'maxlength' => 30,
'placeholder' => 'First Name',
]
)
);
Métodos
Phalcon\Forms\Form exposes a number of methods that help with setting up a form with the necessary elements so that it can be used for validation, rendering elements etc.
public function __construct(
mixed $entity = null,
array $userOptions = []
)
Constructor. Acepta opcionalmente un objeto entity
que será leído internamente. Si las propiedades del objeto contienen propiedades que coinciden con los nombres de los elementos definidos en el formulario, esos elementos serán rellenados con los valores de las propiedades correspondientes de la entidad. La entidad puede ser un objeto Phalcon\Mvc\Model o incluso \stdClass
. El segundo parámetro es userOptions
un vector opcional con datos definidos por el usuario.
NOTE: If the form has the initialize
method present, the constructor will call it automatically with the same parameters
<?php
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Element\Select;
use Phalcon\Forms\Form;
$form = new Form(
null,
[
'phoneTypes' => [
1 => 'Home',
2 => 'Work',
3 => 'Mobile',
],
]
);
$form->add(
new Text(
'nameLast'
)
);
$form->add(
new Text(
'nameFirst'
)
);
$options = $this->getUserOptions();
$phoneTypes = $options['phoneTypes'] ?? [];
$form->add(
new Select(
'phoneType',
$phoneTypes
)
);
If the entity
is passed, and it is not an object, a Phalcon\Forms\Exception will be thrown.
public function add(
ElementInterface $element,
string $position = null,
bool $type = null
): Form
Añade un elemento al formulario. El primer parámetro es un objeto ElementInterface
. El segundo parámetro position
(si se define) es el nombre del elemento existente al que nos dirigimos. El tercer parámetro booleano type
es true
el nuevo elemento será añadido antes del elemento definido en position
. Si no establece o vale null
/false
, el nuevo elemento será añadido después del definido por el parámetro position
.
public function bind(
array $data,
mixed $entity,
array $whitelist = []
): Form
Vincula los datos a la entidad. El primer parámetro data
es un vector de clave/valores. Usualmente es el vector $_POST
. El segundo parámetro entity
es un objeto entidad. Si las propiedades del objeto contienen propiedades que coinciden con los nombres de los elementos de datos
definidos en el formulario, esos elementos serán rellenados con los valores de las propiedades correspondientes de la entidad. La entidad puede ser un objeto Phalcon\Mvc\Model o incluso \stdClass
. El tercer parámetro whitelist
es un vector de elementos permitidos. Cualquier elemento del vector whitelist
que tiene el mismo nombre que un elemento en el vector data
será ignorado.
El método bind
coge el primer vector (ej.$_POST
) y un objeto entidad (ej. Facturas
). Itera sobre el vector y si encuentra una clave que exista en el formulario, le aplica los filtros necesarios (definidos en el formulario) al valor del vector. Posteriormente, comprueba el objeto entidad (Facturas
) y le asigna un valor a cualquier propiedad que coincida con la clave del vector. If a method exists as a setter with the same name as an array key, it will be called first (i.e. name
-> setName()
). Este método permite filtrar rápidamente la entrada de datos y asignarlo al objeto entidad indicado.
<?php
$form->bind($_POST, $customer);
if (true === $form->isValid()) {
$customer->save();
}
If there are no elements in the form, a Phalcon\Forms\Exception will be thrown.
public function clear(mixed $fields = null): Form
Limpia cada elemento del formulario a su valor por defecto. If the passed parameter fields
is a string, only that field will be cleared. Si se indica un vector, todos los elementos del vector serán limpiados. Finalmente, si no se indica nada, todos los elementos serán limpiados.
public function count(): int
Devuelve el número de elementos en la colección
public function current(): ElementInterface | bool
Devuelve el elemento actual de la iteración
public function get(string $name): ElementInterface
Devuelve un elemento añadido al formulario por su nombre. If the element is not found in the form, a Phalcon\Forms\Exception will be thrown.
public function getAction(): string
Devuelve la acción del formulario
public function getAttributes(): Attributes
Devuelve la colección de atributos del formulario. The object returned is Phalcon\Html\Attributes.
public function getElements(): ElementInterface[]
Devuelve los elementos añadidos al formulario
public function getEntity()
Devuelve la entidad relacionada con el modelo
public function getFilteredValue(string $name): mixed | null
Gets a value from the internal filtered data or calls getValue(name)
public function getLabel(string $name): string
Devuelve una etiqueta para un elemento. If the element is not found in the form, a Phalcon\Forms\Exception will be thrown.
public function getMessages(): Messages | array
Devuelve los mensajes generados en la validación.
if (false === $form->isValid($_POST)) {
$messages = $form->getMessages();
foreach ($messages as $message) {
echo $message, "<br>";
}
}
public function getMessagesFor(string $name): Messages
Devuelve los mensajes generados para un elemento específico
public function getTagFactory(): TagFactory | null
Returns the Phalcon\Html\TagFactory
object
public function getUserOption(
string option,
mixed defaultValue = null
): mixed
Devuelve el valor de una opción si está presente. Si la opción no está presente se devolverá defaultValue
.
public function getUserOptions(): array
Devuelve las opciones del elemento
public function getValidation(): ValidationInterface
Devuelve el objeto validador registrado en el formulario
public function getValue(string $name): mixed | null
Obtiene un valor de la entidad interna relacionada o del valor por defecto
public function has(string $name): bool
Comprueba si el formulario contiene un elemento
public function hasMessagesFor(string $name): bool
Comprueba si se han generado mensajes para un elemento específico
public function isValid(
array $data = null,
object $entity = null,
array $whitelist = []
): bool
Valida un formulario. El primer elemento son los datos proporcionados por el usuario. Usualmente el vector $_POST
.
El segundo parámetro opcional es entity
(objeto). If passed, internally the component will call bind()
which will:
- Loop through the passed
data
- Check if the element from the
data
exists (with the same name) in the entity
- If yes, check the form’s whitelist array. If the element exists there, it will not be changed
- The value of the element (from the
data
array) will be sanitized based on the defined filters (if any)
- Call any setters on the
entity
if present
- Assign the value to the property with the same name on the
entity
.
Una vez que el proceso bind()
termina, la entity
modificada se pasará al evento beforeValidation
(si los eventos están activos) y después de que todos los validadores se hayan llamado en el formulario usando el objeto modificado entity
.
NOTE: Passing an entity
object will result in the object being modified by the user input as described above. If you do not wish this behavior, you can clone the entity before passing it, to keep a copy of the original object
<?php
use MyApp\Models\Customers;
use Phalcon\Forms\Form;
$customer = Customers::findFirst();
$form = new Form($customer);
if (true === $form->isValid($_POST, $customer)) {
$customer->save();
}
public function key(): int
Devuelve la clave/posición actual del iterador
public function label(
string $name,
array $attributes = null
): string
Genera la etiqueta de un elemento añadido al formulario incluyendo HTML. El primer parámetro es el nombre del elemento mientras que el segundo es un vector con parámetros opcionales que necesitan ser añadidos a la etiqueta HTML <label>
. Este parámetro puede ser clases CSS por ejemplo. If the element is not found in the form, a Phalcon\Forms\Exception will be thrown.
public function next(): void
Mueve el puntero interno de iteración a la siguiente posición
public function render(
string $name,
array $attributes = []
): string
Renderiza un objeto específico en el formulario. El parámetro vector opcional attributes
se puede usar para indicar parámetros adicionales para el elemento que va a ser renderizado. If the element is not found in the form, a Phalcon\Forms\Exception will be thrown.
public function remove(string $name): bool
Elimina un elemento del formulario
public function rewind(): void
Rebobina el iterador interno
public function setAction(string $action): Form
Establece la acción del formulario
public function setEntity(object $entity): Form
Establece la entidad relacionada con el modelo
public function setAttributes(
Attributes> $attributes
): AttributesInterface
Establece la colección de atributos del formulario
public function setTagFactory(TagFactory $tagFactory): Form
Sets the Phalcon\Html\TagFactory
for the form
public function setValidation(
ValidationInterface $validation
);
Establece el objeto de validación en el formulario.
public function setUserOption(
string $option,
mixed $value
): Form
Establece una opción del formulario definida por el usuario
public function setWhitelist(array $whitelist): Form
Sets the default whitelist
public function setUserOptions(array $options): Form
Establece opciones del formulario definidas por el usuario
public function valid(): bool
Devuelve si el elemento actual en el iterador es válido o no
Inicialización
Los formularios pueden ser inicializados fuera de la clase del formulario añadiéndole elementos. However, you can reuse code or organize your form classes by implementing forms in their own classes:
<?php
use MyApp\Models\PhoneTypes;
use Phalcon\Forms\Element\Select;
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Form;
class CustomersForm extends Form
{
public function initialize()
{
$this->add(
new Text(
'nameLast'
)
);
$this->add(
new Text(
'nameFirst'
)
);
$this->add(
new Select(
'phoneType',
PhoneTypes::find(),
[
'emptyText' => 'Select one...',
'emptyValue' => '',
'useEmpty' => true,
'using' => [
'typ_id',
'typ_name',
],
]
)
);
}
}
También podemos pasar en el constructor un vector de opciones definidas por el usuario, que ofrecerá más funcionalidad.
<?php
use MyApp\Models\Customers;
use Phalcon\Forms\Element\Hidden;
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Form;
class CustomersForm extends Form
{
public function initialize(
Customers $customer,
array $options
) {
$mode = $options['mode'] ?? 'view';
if ('edit' === $mode) {
$this->add(
new Hidden(
'id'
)
);
}
$this->add(
new Text(
'nameLast'
)
);
$this->add(
new Text(
'nameFirst'
)
);
}
}
El la instanciación del formulario usarás:
<?php
use MyApp\Models\Customers;
$form = new CustomersForm(
new Customers(),
[
'mode' => 'edit',
]
);
El código anterior comprobará el vector options
durante el método initialize
. El código comprobará el elemento mode
en el vector y si no está presente por defecto será view
. If the mode
is edit
, we are going to add a Phalcon\Forms\Element\Hidden element with the entity’s ID in the form. Usando el vector option
podemos crear formularios reutilizables y también pasar datos adicionales en nuestros formularios que pueden ser requeridos.
Entidades
Una entidad como Phalcon\Mvc\Model, una clase PHP o incluso un objeto \stdClass
se pueden pasar al formulario para establecer los valores por defecto, o para asignar los valores del formulario al objeto.
<?php
use MyApp\Models\Customers;
use Phalcon\Forms\Form;
$customer = Customers::findFirst();
$form = new Form($customer);
$form->add(
new Text(
'nameFirst'
)
);
$form->add(
new Text(
'nameLast'
)
);
Una vez que el formulario se ha renderizado, si no hay valores por defecto asignados a los elementos, se usarán los proporcionados por la entidad:
<?php echo $form->render('nameLast'); ?>
Puede validar el formulario y asignar a la entidad los valores introducidos por el usuario como sigue:
<?php
use MyApp\Models\Customers;
use Phalcon\Forms\Form;
$customer = Customers::findFirst();
$form = new Form($customer);
$form->bind($_POST, $customer);
if (true === $form->isValid()) {
$customer->save();
}
En el ejemplo anterior, obtenemos el primer registro Customer
. Pasamos ese objeto a nuestro formulario para rellenarlo con valores iniciales. A continuación llamamos al método bind
con la entidad y el vector $_POST
. El formulario automáticamente filtrará la entrada desde $_POST
y la asignará al objeto entidad (Customers
). Podemos guardar el objeto si el formulario ha superado la validación.
También podemos usar una clase PHP como entidad:
<?php
class Preferences
{
public string $timezone = 'Europe/Amsterdam';
public string $receiveEmails = 'No';
}
Usando esta clase como entidad, permite al formulario coger los valores por defecto de ella:
<?php
$form = new Form(
new Preferences()
);
$form->add(
new Select(
'timezone',
[
'America/New_York' => 'New York',
'Europe/Amsterdam' => 'Amsterdam',
'America/Sao_Paulo' => 'Sao Paulo',
'Asia/Tokyo' => 'Tokyo',
]
)
);
$form->add(
new Select(
'receiveEmails',
[
'Yes' => 'Yes, please!',
'No' => 'No, thanks',
]
)
);
Las entidades pueden implementar getters
, que son más prioritarios que las propiedades públicas. Estos métodos ofrecen más flexibilidad para generar valores:
<?php
class Preferences
{
public string $timezone;
public string $receiveEmails;
public function getTimezone(): string
{
return 'Europe/Amsterdam';
}
public function getReceiveEmails(): string
{
return 'No';
}
}
Para la clase de la entidad anterior, se usarán los métodos getReceiveEmails
y getTimezone
en lugar de las propiedades receiveEmails
y timezone
.
Elementos
Phalcon provee un conjunto de elementos integrados para usar en sus formularios, todos esos elementos se localizan en el espacio de nombres Phalcon\Forms\Element
:
These elements use the Phalcon\Html\TagFactory component transparently.
NOTE: For more information regarding HTML elements, you can check our TagFactory document
NOTE: The Phalcon\Forms\Element\Check
and Phalcon\Forms\Element\Radio
classes now use the Phalcon\Html\Helper\Input\Checkbox
and Phalcon\Html\Helper\Input\Radio
respectively. The classes use checked
and unchecked
parameters to set the state of each control. If the checked
parameter is identical to the $value
then the control will be checked. If the unchecked
parameter is present, it will be set if the $value
is not the same as the checked
parameter. more
The Phalcon\Forms\Element\Select supports the useEmpty
option to enable the use of a blank element within the list of available options. Las opciones emptyText
y emptyValue
son opcionales, las cuales le permiten personalizar, respectivamente, el texto y el valor del elemento vacío
You can also create your own elements by extending the Phalcon\Forms\Element\AbstractElement abstract class.
<?php
use Phalcon\Forms\Element\AbstractElement ;
class MyElement extends AbstractElement
{
public function render($attributes = null)
{
$html = '';// HTML
return $html;
}
}
Reserved names
Because of the way forms work and interact with elements, certain names are reserved and cannot be used as element names. These names are:
action
attributes
di
elements
entity
eventsmanager
messages
messagesfor
label
tagFactory
useroption
useroptions
validation
value
These names correspond to getters in the Form
object or are properties coming from the Di container.
Filtrando
Un formulario también es capaz de filtrar los datos antes de ser validado. Puede configurar filtros para cada elemento:
<?php
use Phalcon\Filter\Filter;
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Form;
$form = new Form();
$name = new Text('nameLast');
$name->setFilters(
[
'string', // Filter::FILTER_STRING
'trim', // Filter::FILTER_TRIM
]
);
$form->add($name);
$email = new Text('email');
$email->setFilters(
'email'
);
$form->add($email);
NOTE: For more information regarding filters, you can check our Filter document
Validación
Phalcon forms are integrated with the validation component to offer instant validation. Los validadores integrados o personalizados se pueden configurar para cada elemento:
<?php
use Phalcon\Forms\Element\Text;
use Phalcon\Validation\Validator\PresenceOf;
use Phalcon\Validation\Validator\StringLength;
$name = new Text(
'nameLast'
);
$name->addValidator(
new PresenceOf(
[
'message' => 'The name is required',
]
)
);
$name->addValidator(
new StringLength(
[
'min' => 10,
'messageMinimum' => 'The name is too short',
]
)
);
$form->add($name);
Entonces puede validar el formulario acorde a los datos introducidos por el usuario:
<?php
if (false === $form->isValid($_POST)) {
$messages = $form->getMessages();
foreach ($messages as $message) {
echo $message, '<br>';
}
}
Los validadores son ejecutados en el mismo orden en el que fueron registrados.
By default, messages generated by all the elements in the form are joined, so they can be traversed using a single foreach
. También puede obtener mensajes específicos de un elemento:
<?php
$messages = $form->getMessagesFor('nameLast');
foreach ($messages as $message) {
echo $message, '<br>';
}
Renderizado
Puede renderizar el formulario con total flexibilidad, el siguiente ejemplo muestra como renderizar cada elemento usando un procedimiento estándar:
<form method='post'>
<?php
// Traverse the form
foreach ($form as $element) {
// Get any generated messages for the current element
$messages = $form->getMessagesFor(
$element->getName()
);
if (count($messages)) {
// Print each element
echo '<div class="messages">';
foreach ($messages as $message) {
echo $message;
}
echo '</div>';
}
echo '<p>';
echo '<label for="' .
$element->getName() .
'">' .
$element->getLabel() .
'</label>'
;
echo $element;
echo '</p>';
}
?>
<input type='submit' value='Send' />
</form>
O reutilizar la lógica de tu clase formulario:
<?php
use Phalcon\Forms\Form;
class ContactForm extends Form
{
public function initialize()
{
// ...
}
public function renderDecorated($name)
{
$element = $this->get($name);
$messages = $this->getMessagesFor(
$element->getName()
);
if (count($messages)) {
echo "<div class='messages'>";
foreach ($messages as $message) {
echo $this->flash->error($message);
}
echo '</div>';
}
echo '<p>';
echo '<label for="' .
$element->getName() .
'">' .
$element->getLabel() .
'</label>';
echo $element;
echo '</p>';
}
}
En la vista:
<?php
echo $element->renderDecorated('nameLast');
echo $element->renderDecorated('nameFirst');
Eventos
Cuando los formularios se implementan como clases, las llamadas de retorno: los métodos beforeValidation()
y afterValidation()
se pueden implementar en la clase del formulario para ejecutar pre-validaciones y post-validaciones:
<?php
use Phalcon\Forms\Form;
class ContactForm extends Form
{
public function beforeValidation()
{
}
}
Manager
This component provides the Phalcon\Forms\Manager that can be used by the developer to register forms and access them via the service locator:
<?php
use Phalcon\Di\FactoryDefault;
use Phalcon\Forms\Manager;
$container = new FactoryDefault();
$container->set(
'forms',
function () {
return new Manager();
}
);
Los formularios se añaden al gestor de formularios y se referencian por un nombre único:
<?php
$this
->forms
->set(
'login',
new LoginForm()
)
;
Usando el nombre único, se puede acceder a los formularios desde cualquier parte de la aplicación:
<?php
$loginForm = $this->forms->get('login');
echo $loginForm->render();
If a form is not found in the manager, a Phalcon\Forms\Exception will be thrown.
Excepciones
Any exceptions thrown in the Phalcon\Forms
namespace will be Phalcon\Forms\Exception. Puede usar estas excepciones para capturar selectivamente sólo las excepciones lanzadas desde este componente.
<?php
use Phalcon\Forms\Exception;
use Phalcon\Forms\Manager;
use Phalcon\Mvc\Controller;
/**
* @property Manager $forms
*/
class IndexController extends Controller
{
public function index()
{
try {
$this->forms->get('unknown-form');
} catch (Exception $ex) {
echo $ex->getMessage();
}
}
}
Inyección de Dependencias
Phalcon\Forms\Form extends Phalcon\Di\Injectable, so you have access to the application services if needed:
<?php
use Phalcon\Forms\Element\Hidden;
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Form;
use Phalcon\Security;
/**
* @property Security $security
*/
class ContactForm extends Form
{
public function initialize()
{
// Set the same form as entity
$this->setEntity($this);
// Add a text element to capture the 'email'
$this->add(
new Text(
'email'
)
);
// Add a text element to put a hidden CSRF
$this->add(
new Hidden(
'csrf'
)
);
}
public function getCsrf()
{
return $this->security->getToken();
}
}
Recursos Adicionales
- Vökuró, es una aplicación de ejemplo que usa el constructor de formularios para crear y gestionar formularios, [GitHub]