Альтернативой использования фильтра Callback
является написание своего собственного класса фильтра,
реализующего интерфейс FilterInterface
. Фильтр затем можно будет использовать в формах вашего веб-приложения
(или, при желании, вне форм).
Чтобы продемонстрировать создание своего фильтра, мы напишем класс PhoneFilter
, инкаспулирующий
алгоритм фильтрации номера, который мы использовали в примере фильтра Callback
.
Как вы возможно помните, базовым классом для всех стандартных фильтров является класс
AbstractFilter
. По аналогии мы также будем наследовать наш фильтрPhoneFilter
от этого базового класса.
Мы планируем иметь следующие методы в классе фильтра PhoneFilter
(см. таблицу 8.18):
Имя метода | Описание |
---|---|
__construct($options) |
Конструктор - принимает опциональный аргумент $options , который нужен для того, чтобы сразу задать опции фильтра. |
setFormat($format) |
Задает опцию формата номера. |
getFormat() |
Возвращает опцию формата номера. |
filter($value) |
Запускает фильтр. |
Сперва создайте файл PhoneFilter.php в каталоге Filter под корневым каталогом модуля 28. Поместите в этот файл следующий код:
28) Класс PhoneFilter
можно считать моделью сервиса, так как его задачей является
обработка данных, а не их хранение. Все пользовательские фильтры принято хранить под каталогом Filter
.
<?php
namespace Application\Filter;
use Zend\Filter\AbstractFilter;
// Этот класс фильтра предназначен для преобразования произвольного номера телефона в
// локальный или международный формат.
class PhoneFilter extends AbstractFilter
{
// Константы форматов номера.
const PHONE_FORMAT_LOCAL = 'local'; // Local phone format
const PHONE_FORMAT_INTL = 'intl'; // International phone format
// Доступные опции фильтра.
protected $options = [
'format' => self::PHONE_FORMAT_INTL
];
// Конструктор.
public function __construct($options = null)
{
// Задает опции фильтра (если они предоставлены).
if(is_array($options)) {
if(isset($options['format']))
$this->setFormat($options['format']);
}
}
// Задает формат номера.
public function setFormat($format)
{
// Проверяет входной аргумент.
if( $format!=self::PHONE_FORMAT_LOCAL &&
$format!=self::PHONE_FORMAT_INTL ) {
throw new \Exception('Invalid format argument passed.');
}
$this->options['format'] = $format;
}
// Возвращает формат номера.
public function getFormat()
{
return $this->format;
}
// Фильтрует телефонный номер.
public function filter($value)
{
if(!is_scalar($value)) {
// Возвращаем нескалярное значение неотфильтрованным.
return $value;
}
$value = (string)$value;
if(strlen($value)==0) {
// Возвращаем пустое значение неотфильтрованным.
return $value;
}
// Сперва удаляем все нецифровые символы.
$digits = preg_replace('#[^0-9]#', '', $value);
$format = $this->options['format'];
if($format == self::PHONE_FORMAT_INTL) {
// Дополняем нулями, если число цифр некорректно.
$digits = str_pad($digits, 11, "0", STR_PAD_LEFT);
// Добавляем скобки, пробелы и тире.
$phoneNumber = substr($digits, 0, 1) . ' (' .
substr($digits, 1, 3) . ') ' .
substr($digits, 4, 3) . '-' .
substr($digits, 7, 4);
} else { // self::PHONE_FORMAT_LOCAL
// Дополняем нулями, если число цифр некорректно
$digits = str_pad($digits, 7, "0", STR_PAD_LEFT);
// Добавляем тире.
$phoneNumber = substr($digits, 0, 3) . '-'. substr($digits, 3, 4);
}
return $phoneNumber;
}
}
Как видите из строки 2 класс фильтра содержится в пространстве имен Application\Filter
.
В строке 8 мы определяем класс PhoneFilter
. Мы наследуем наш фильтр от базового класса
AbstractFilter
для повторного использования предоставляемой им функциональности. Строка 4
содержит псевдоним для класса AbstractFilter
.
В строках 11-12 мы для удобства определяем константы форматов номера (PHONE_FORMAT_INTL
для
международного формата и PHONE_FORMAT_LOCAL
для локального). Эти константы - эквиваленты
строк "intl" и "local" соответственно.
В строках 15-17 мы определяем private-переменную $options
, которая является массивом, имеющим
один единственный ключ под названием "format". Этот ключ будет содержать опцию формата номера для
нашего фильтра.
В строках 20-28 находится метод конструктора, который принимает один аргумент $options
.
При создании фильтра вручную, этот параметр можно пропустить. Однако, когда фильтр создается
классом фабрики, фабрика будет передавать опции фильтра его конструктору через этот аргумент.
В строках 31-40 и 43-46 находятся методы setFormat()
и getFormat()
, позволяющие соответственно
задать и извлечь текущий формат номера.
В строках 49-86 находится метод filter()
. Этот метод инкапсулирует алгоритм фильтрации телефонного
номера. Он принимает параметр $value
, преобразовывает его с учетом выбранного формата номера
и возвращает отформатированный номер телефона.
Как только класс фильтра PhoneFilter
будет готов, вы легко можете начать его использовать в
форме обратной связи (или других формам) как показано ниже. Предполагается, что вы вызываете
следующий код внутри метода ContactForm::addInputFilter()
:
$inputFilter->add([
'name' => 'phone',
'required' => true,
'filters' => [
[
'name' => PhoneFilter::class,
'options' => [
'format' => PhoneFilter::PHONE_FORMAT_INTL
]
],
// ...
],
// ...
]);
Вы можете посмотреть, как работает фильтр PhoneFilter
в примере Form Demo - приложении, которое идет
вместе с этой книгой. Откройте страницу "http://localhost/contactus" в своем браузере. Если вы введете
какой-либо телефонный номер в некорректном формате, фильтр исправит номер.
Если хотите, можете использовать PhoneFilter
вне форм, как показано во фрагменте кода ниже:
<?php
use Application\Filter\PhoneFilter;
// Создаем фильтр PhoneFilter.
$filter = new PhoneFilter();
// Настраиваем фильтр.
$filter->setFormat(PhoneFilter::PHONE_FORMAT_INTL);
// Фильтруем строку.
$filteredValue = $filter->filter('12345678901');
// Ожидаемый вывод фильтра - '1 (234) 567-8901'.