Extending Zend Form Element to create customized Phone number field

Generally, Phone numbers has different parts. Such as, country code, operator code and subscriber number etc. When taking Phone number as user input, we can worn users about phone number format by setting a hint/description and can validate using Regular Expression. But, for better usability, along with hints, some web applications provide separate (generally 3) text fields for different parts of phone number. Also, some of them keep a separator, ‘-‘ or ‘#’ between this fields.

Now, if we try provide this feature in Zend Form, that’s possible. We can create three individual Zend_Form_Element_Text objects and join there value together to make the phone number. But, in this case, validating them together is a hassle. Again, placing them inline in the form and putting separators needs some Decorator magic. What if we can make it simply another Zend Form Element which renders three text box (optionally with separator)? And consider their value jointly and validate them together using ordinary Zend Validators? Lets try.

What we are going to make?

Let’s visualize our Phone number field first and list what we want from it.

  • It’s Simple. It’s rendering, validation everything is like any other ordinary Zend From Elements.
  • It prints 3 text boxes for different parts of Phone number.
  • When we validate it or take it’s value, the input of these three boxes jointly will be considered as the value.
  • We can set a separator character to be printed between text boxes.
  • We can include/exclude this separators from value.

Assumptions

Assuming that, you have used Zend_Form, Zend_From_Element_* and understand how the directory hierarchy, naming convention, Autoloading of Zend works. Also, in library directory, you keep a directory beside Zend for additional project based classes. We will refer it as Project directory and classes under it will be Project_<dir-name>_<class> etc.

Let’s do it

It’s already done :). So, please download it first.


Now I will go through the code and will tell you how it’s working. The form element class is created in “Project/Form/Element/Phone.php”. So our class name is Project_Form_Element_Phone. This class is extending Zend_Form_Element_Xhtml for getting common form element functionalities by default. Then, declared some public properties as below –

  • $codeLength : array. default lengths of phone number parts
  • $ignoreSeperator : boolean. flag for ignoring/including separator characters in value
  • $helper : Name of default form view helper to use for rendering

In constructor, checking if codeLength and ignoreSeperator is set as attribute (using Zend_Form_Element::setAttrib). If not, adding them with attributes array with default values. Then calling parent’s constructor. Also, overwriting isValid() function for joining values of three parts. From where these 3 parts coming? Find the answer in view helper which rendering this filed.

Each Zend Form Element needs a view helper to be rendered with. Our view helper for Project_Form_Element_Phone is at “Project/View/Helper/FormPhone.php”. So, set the value of Project_Form_Element_Phone::$helper as ‘formPhone’. The secret is here, in formPhone() function. Here, I am printing three text fields named <filed-name>_country, <filed-name>_operator and <filed-name>. They will have additional class name phone_country, phone_operator and phone respectively so that we can style them from CSS. Also, the length of each part will be set as maxlength.

Check ‘Project/View/Helper/’ has been added as HelperPath and ‘Project_’ is added in Autoloader Namespaces.

BTW, if you still fetch problem in loading files or don’t want to use separate directory (referred as Project) for additional classes, you can put the Phone.php in “Zend/Form/Element” and FormPhone.php in “Zend/View/Helper” directory. Then change the class names.

How to use?

Seems everything is done. Let’s see an example how it will be used.

[php]

$primaryPhone = new Project_Form_Element_Phone(‘primary_phone’);

$primaryPhone->setLabel(‘Primary phone’)
->setAttrib(‘class’ ,’some class’ )
->setAttrib(‘separator’ ,’#’ ) // Separator between Phone number parts
->setAttrib(‘ignoreSeparator’, true) // Ignore seperators from in field value
->setDescription(‘Phone number format: XXX # XXXX # XXXXXX’)
->setValue(isset($data[‘primary_phone’]) ? $data[‘primary_phone’] : ”)
->addValidator(‘digits’);

$form->addElement($primaryPhone);

[/php]

So, is all our expectations in above list full-fulled?

14 Comments

  1. Nice post, it’s incredible the flexibility that ZF gives to us developers, and it’s much more incredible how the Zend_Form has evolved to a great component. Congratulations! Regards.

  2. Do you think about use variable $codeLenght in __contruct method to freely manipulate the lenght?
    Well done. It show how you can customize ZF. Not like the other frameworks;)

  3. Thank you! Very helpful.
    There is a typo in the attribute $attribs[‘maxlenght’]
    should be
    $attribs[‘maxlength’]

  4. I hope you guys dont mind, but you guys really seem tuned in. Me (?) LOST 🙂

    Does anyone know where I can get code info on searching for a “13” digit number in one of my tables? The display page does not change when I search for this number in a text box.

    script is:

    Find Results with:
    Any of these words:
    All of these words:
    None of these words:

    <?
    } else if($c) {
    MySQL_connect("xxxxxxx", "xx", "xxxxxx");
    MySQL_select_db("database");
    if((!$all) || ($all == "")) { $all = ""; } else { $all = "+(".$all.")"; }
    if((!$any) || ($any == "")) { $any = ""; }
    if((!$none) || ($none == "")) { $none = ""; } else { $none = "-(".$none.")"; }
    $query = "
    SELECT *,
    MATCH(digits) AGAINST ('$all $none $any' IN BOOLEAN MODE) AS score
    FROM users
    WHERE MATCH(digits) AGAINST ('$all $none $any' IN BOOLEAN MODE)";
    $artm1 = MySQL_query($query);
    if(!$artm1) {
    echo MySQL_error()."$query”;
    }
    echo “Article Matches“;
    if(MySQL_num_rows($artm1) > 0) {
    echo “”;
    echo “Score Title Body”;
    while($artm2 = MySQL_fetch_array($artm1)) {
    $val = round($artm2[‘score’], 3);
    $val = $val*100;
    echo “$val”;
    echo “{$artm2[‘title’]}”;
    echo “{$artm2[‘body’]}”;
    }
    echo “”;
    }
    else {
    echo “No Results were found in this category.”;
    }
    echo “”;
    }

    ?>

  5. Hi, looks like you’ve rearranged your site since you wrote this article!

    Now the link from this page on the Zend devzone site doesn’t work:

    http://devzone.zend.com/1778/extending-zend-form-element-to-create-customized-phone-number-field/

    I was able to find the article pretty easily, but you might want to write a redirect rule to automatically forward visitors to the new URL.

    Also, do you have a new location for the source code download, as the link in this article is broken 🙁

    Thanks, and nice work!

Leave a Reply to Peter Cancel reply

Your email address will not be published. Required fields are marked *