An alternative to using the Callback
filter is writing your own filter class
implementing the FilterInterface
interface. Then, this filter may be used in
forms of your web application (or, if you wish, outside a form).
To demonstrate how to create your own filter, we will write the PhoneFilter
class encapsulating
the phone filtering algorithm we used with the Callback
filter example.
As you may remember, the base concrete class for all standard filters is the
AbstractFilter
class. By analogy, we will also derive our customPhoneFilter
filter from that base class.
We plan to have the following methods in our PhoneFilter
filter class (see table 8.18):
Method name | Description |
---|---|
__construct($options) |
Constructor - accepts an optional argument $options , which is needed to set filter options at once. |
setFormat($format) |
Sets the phone format option. |
getFormat() |
Returns the phone format option. |
filter($value) |
Runs the phone filter. |
To start, create the PhoneFilter.php file in the Filter directory under the module's source directory 28. Put the following code into that file:
28) The PhoneFilter
class may be considered as a service model because its goal is to
process data, not to store it. By convention, we store all custom filters under the Filter
directory.
<?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;
}
}
From line 2, you can see that the filter class lives in the Application\Filter
namespace.
In line 8, we define the PhoneFilter
class. We derive our filter class from
the AbstractFilter
base class to reuse the functionality it provides. Line 4 contains
the short alias for the AbstractFilter
class.
In lines 11-12, for convenience, we define the phone format constants (PHONE_FORMAT_INTL
for
international format and PHONE_FORMAT_LOCAL
for local format). These are the equivalents of the
"intl" and "local" strings, respectively.
In lines 15-17, we define the $options
private variable, which is an array having the single key
named "format". This key will contain the phone format option for our filter.
In lines 20-28, we have the constructor method, which takes the single argument $options
.
When constructing the filter manually, you may omit this parameter. However, when the filter is
constructed by the factory class, the factory will pass filter options to the filter's constructor
through this argument.
In lines 31-40 and 43-46, we have the setFormat()
and getFormat()
methods that allow to set and
retrieve the current phone format, respectively.
In lines 49-86, we have the filter()
method. This method encapsulates the phone number filtering
algorithm. It takes the $value
parameter, transforms it by taking the selected phone format in
account, and returns the formatted phone number.
When the PhoneFilter
filter class is ready, you can easily start using it in the feedback form
(or in another form) as follows. It is assumed that you call the following code inside of the
ContactForm::addInputFilter()
method:
$inputFilter->add([
'name' => 'phone',
'required' => true,
'filters' => [
[
'name' => PhoneFilter::class,
'options' => [
'format' => PhoneFilter::PHONE_FORMAT_INTL
]
],
// ...
],
// ...
]);
You can see how the PhoneFilter
filter works in the Form Demo sample application bundled with
this book. Open the "http://localhost/contactus" page in your web browser. If you enter some phone
number in an incorrect format, the filter will fix the phone number.
If you wish, you can use the PhoneFilter
outside of forms, as shown in the code example below:
<?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'.