2

I want to validate a form element that is allowed to contain multiple email addresses, separated by a comma and a space.

Here's the code I have:

class My_Validate_EmailAddresses extends Zend_Validate_Abstract
{
    const MSG_INVALID = 'msgInvalid';

    /** @var Zend_Validate_EmailAddress */
    protected static $_validatorEmailAddress;

    /** @var array */
    protected $_messageTemplates = array(
        self::MSG_INVALID => "'%value%' is not a valid email address",
    );

    /**
     *
     * @return Zend_Validate_EmailAddress
     */
    public static function getValidatorEmailAddress()
    {
        if (is_null(self::$_validatorEmailAddress)) {
            self::$_validatorEmailAddress = new Zend_Validate_EmailAddress();
        }
        return self::$_validatorEmailAddress;
    }

    /**
     * Values passed in here should be filterd by My_Filter_CommaSpaceSeparated first
     *
     * @param string $value
     * @return boolean
     */
    public function isValid($value)
    {
        $valid = true;
        $emails = explode(', ', $value);
        foreach ($emails as $email) {
            if (!self::getValidatorEmailAddress()->isValid($email)) {
                $this->_error(self::MSG_INVALID, $email);
                $valid = false;
            }
        }
        return $valid;
    }
}

It correctly validates, but if there is more than one email address in the list that doesn't validate, only the error message for the final one is shown. I would like see a message for each invalid email address.

Sonny
  • 8,204
  • 7
  • 63
  • 134

2 Answers2

3

I worked around the multiple messages issue by using the email address as the message key int the $_messageTemplates array. I also created a single email validation class and then extended it for multiple validation.

Single Email Address

class My_Validate_EmailAddress extends Zend_Validate_Abstract
{
    const MSG_INVALID = "'%value%' is not a valid email address";

    /** @var Zend_Validate_EmailAddress */
    protected static $_validatorEmailAddress;

    /** @var array */
    protected $_messageTemplates = array();

    /**
     *
     * @return Zend_Validate_EmailAddress
     */
    public static function getValidatorEmailAddress()
    {
        if (is_null(self::$_validatorEmailAddress)) {
            self::$_validatorEmailAddress = new Zend_Validate_EmailAddress();
        }
        return self::$_validatorEmailAddress;
    }

    /**
     *
     * @param string $value
     * @return boolean
     */
    public function isValid($value)
    {
        $valid = true;
        if (!self::getValidatorEmailAddress()->isValid($value)) {
            $this->_messageTemplates[$value] = self::MSG_INVALID;
            $this->_error($value, $value);
            $valid = false;
        }
        return $valid;
    }
}

Multiple Email Addresses

class My_Validate_EmailAddresses extends My_Validate_EmailAddress
{
    /**
     * Values passed in here should be filterd by My_Filter_CommaSpaceSeparated first
     *
     * @param string $value
     * @return boolean
     */
    public function isValid($value)
    {
        $valid = true;
        $emails = explode(', ', $value);
        foreach ($emails as $email) {
            if (!parent::isValid($email)) {
                $valid = false;
            }
        }
        return $valid;
    }
}

Comma and Space Filter

class My_Filter_CommaSpaceSeparated implements Zend_Filter_Interface
{
    /**
     *
     * @param string $value
     * @return string
     */
    public function filter($value)
    {
        // normalize delimiters
        $value = str_replace(array(' ', ';'), ',', $value);
        // explode values
        $values = explode(',', $value);
        // remove empty values
        $values = array_filter($values);
        // implode
        $value = implode(', ', $values);
        // return filtered value
        return $value;
    }
}
Sonny
  • 8,204
  • 7
  • 63
  • 134
2

You cannot do that by virtue of the current implementation of $this->_error () method. But you can put all non-validating emails into a string and then pass it to the _error ().

    $wrong_emails = array ();
    foreach ($emails as $email) {
         if (!self::getValidatorEmailAddress()->isValid($email)) {
               $wrong_emails [] = $email;
         }
    }
    if ($wrong_emails)
    {
         $this->_error(self::MSG_INVALID, join (', ', $wrong_emails);
         return false;
    }

return true;
akond
  • 15,865
  • 4
  • 35
  • 55
  • Thanks akond! I was thinking that I'd have to go this route, but I found another way that I like better. I will be posting it shortly. – Sonny Dec 08 '11 at 17:48
  • Just posted it. Thanks again for your solution, it may be a better solution for a different situation than mine. – Sonny Dec 08 '11 at 17:58