Una alternativa al uso del filtro Callback
es escribir nuestra propia clase
filtro implementando la interfaz FilterInterface
. Este filtro se puede usar
en los formularios de la aplicación web o si lo deseamos fuero del formulario.
Para demostrar como crear nuestro propio filtro escribiremos la clase PhoneFilter
que encapsula el algoritmo de filtrado de número de teléfonos que usamos en el
ejemplo del filtro Callback
.
Como podemos recordar, la clase concreta base para todos los filtros estándares es la clase
AbstractFilter
. Por analogía, también derivaremos nuestro filtro personalizadoPhoneFilter
de la clase base.
Planeamos tener los siguientes métodos en nuestra clase filtro PhoneFilter
(ver tabla 8.18):
Nombre del método | Descripción |
---|---|
__construct($options) |
Constructor. Acepta opcionalmente el argumento $options que se usa para asignar las opciones del filtro de una vez. |
setFormat($format) |
Asigna la opción de formato de número. |
getFormat() |
Regresa la opción de formato de número. |
filter($value) |
Ejecuta el filtro de teléfono. |
Para comenzar, creamos el archivo PhoneFilter.php en la carpeta Filter dentro de la carpeta fuente del módulo 28. Luego, colocamos el siguiente código dentro del archivo:
28) La clase PhoneFilter
se puede considerar como un modelo
de servicio porque su objetivo es procesar datos, no guardarlos.
Por convención, guardamos todos los filtros personalizados
dentro de la carpeta Filter
.
<?php
namespace Application\Filter;
use Zend\Filter\AbstractFilter;
// This filter class is designed for transforming an arbitrary phone number to
// the local or the international format.
class PhoneFilter extends AbstractFilter
{
// Phone format constants.
const PHONE_FORMAT_LOCAL = 'local'; // Local phone format
const PHONE_FORMAT_INTL = 'intl'; // International phone format
// Available filter options.
protected $options = [
'format' => self::PHONE_FORMAT_INTL
];
// Constructor.
public function __construct($options = null)
{
// Set filter options (if provided).
if(is_array($options)) {
if(isset($options['format']))
$this->setFormat($options['format']);
}
}
// Sets phone format.
public function setFormat($format)
{
// Check input argument.
if( $format!=self::PHONE_FORMAT_LOCAL &&
$format!=self::PHONE_FORMAT_INTL ) {
throw new \Exception('Invalid format argument passed.');
}
$this->options['format'] = $format;
}
// Returns phone format.
public function getFormat()
{
return $this->format;
}
// Filters a phone number.
public function filter($value)
{
if(!is_scalar($value)) {
// Return non-scalar value unfiltered.
return $value;
}
$value = (string)$value;
if(strlen($value)==0) {
// Return empty value unfiltered.
return $value;
}
// First, remove any non-digit character.
$digits = preg_replace('#[^0-9]#', '', $value);
$format = $this->options['format'];
if($format == self::PHONE_FORMAT_INTL) {
// Pad with zeros if the number of digits is incorrect.
$digits = str_pad($digits, 11, "0", STR_PAD_LEFT);
// Add the braces, the spaces, and the dash.
$phoneNumber = substr($digits, 0, 1) . ' (' .
substr($digits, 1, 3) . ') ' .
substr($digits, 4, 3) . '-' .
substr($digits, 7, 4);
} else { // self::PHONE_FORMAT_LOCAL
// Pad with zeros if the number of digits is incorrect.
$digits = str_pad($digits, 7, "0", STR_PAD_LEFT);
// Add the dash.
$phoneNumber = substr($digits, 0, 3) . '-'. substr($digits, 3, 4);
}
return $phoneNumber;
}
}
En la línea 2 podemos ver que la clase filtro está en el espacio de nombres
Application\Filter
.
En la línea 8 definimos la clase PhoneFilter
. Derivamos nuestra clase filtro
de la clase base AbstractFilter
para reusar las funcionalidades que provee.
La línea 4 contiene el alias de la clase AbstractFilter
.
En las líneas 11-12, por convención, definimos los formatos de número de teléfono
como constantes (PHONE_FORMAT_INTL
para el formato internacional y PHONE_FORMAT_LOCAL
para el formato local). Estos son respectivamente los equivalentes de «intl» y
«local».
En las líneas 15-17, definimos la variable privada $options
que es un arreglo
que tiene una sola llave llamada «format». Esta llave contiene la opción de formato
del número de teléfono para nuestro filtro.
En las líneas 20-28, tenemos el método constructor que solamente toma el argumento
$options
. Cuando construimos el filtro manualmente podemos omitir este parámetro.
Sin embargo, cuando el filtro es construido por la clase fábrica, la fábrica pasará
las opciones del filtro al constructor del filtro por medio de este argumento.
En las líneas 31-40 y 43-46 tenemos los métodos setFormat()
y getFormat()
que permiten respectivamente colocar y recuperar el formato del número de teléfono.
En las líneas 49-86 está el método filter()
. Este método encapsula el algoritmo
que filtra el número de teléfono. El método toma el parámetro $value
transformándolo
de acuerdo con el formato del número telefónico seleccionado y regresándolo formateado.
Cuando la clase filtro PhoneFilter
está lista podemos fácilmente comenzar a
usarla en el formulario de contacto (o en otro formulario) de la siguiente
manera. Estamos suponiendo que llamamos el siguiente código dentro del método
ContactForm::addInputFilter()
:
$inputFilter->add([
'name' => 'phone',
'required' => true,
'filters' => [
[
'name' => PhoneFilter::class,
'options' => [
'format' => PhoneFilter::PHONE_FORMAT_INTL
]
],
// ...
],
// ...
]);
Podemos ver como el filtro PhoneFilter
trabaja en el ejemplo Form Demo, la
aplicación de ejemplo que está junto a este libro. Abrimos la página
«http://localhost/contactus» en nuestro navegador web. Si ingresamos algún
número de teléfono en un formato incorrecto el filtro corregirá el número de
teléfono.
Si lo deseamos podemos usar la clase PhoneFilter
fuera de los formularios como
se muestra más abajo:
<?php
use Application\Filter\PhoneFilter;
// Create PhoneFilter filter.
$filter = new PhoneFilter();
// Configure the filter.
$filter->setFormat(PhoneFilter::PHONE_FORMAT_INTL);
// Filter a string.
$filteredValue = $filter->filter('12345678901');
// The expected filter's output is the '1 (234) 567-8901'.