MrNorm
MrNorm

Reputation: 406

ZF2 - Show just one error on forms

I can't seem to get ZF2 to show just one error message for failed form validation messages.

For example, an EmailAddress validator can pass back up to 7 messages and typically shows the following if the user has made a typo:

oli.meffff' is not a valid hostname for the email address
The input appears to be a DNS hostname but cannot match TLD against known list
The input appears to be a local network name but local network names are not allowed

How can I override the error to show something a little more friendly, such as "Please enter a valid email address" instead of specifics like the above?

Upvotes: 1

Views: 1304

Answers (1)

MrNorm
MrNorm

Reputation: 406

OK, managed to come up with a solution for this. Instead of using the same string as the error for all validator failures as Sam suggested above, I have overridden the error messages in the InputFilter for the elements and then used a custom form error view helper to show only the first message.

Here is the helper:

<?php
namespace Application\Form\View\Helper;

use Traversable;
use \Zend\Form\ElementInterface;
use \Zend\Form\Exception;

class FormElementSingleErrors extends \Zend\Form\View\Helper\FormElementErrors
{
    /**
     * Render validation errors for the provided $element
     *
     * @param  ElementInterface $element
     * @param  array $attributes
     * @throws Exception\DomainException
     * @return string
     */
    public function render(ElementInterface $element, array $attributes = array())
    {
        $messages = $element->getMessages();
        if (empty($messages)) {
            return '';
        }
        if (!is_array($messages) && !$messages instanceof Traversable) {
            throw new Exception\DomainException(sprintf(
                '%s expects that $element->getMessages() will return an array or Traversable; received "%s"',
                __METHOD__,
                (is_object($messages) ? get_class($messages) : gettype($messages))
            ));
        }

        // We only want a single message
        $messages = array(current($messages));

        // Prepare attributes for opening tag
        $attributes = array_merge($this->attributes, $attributes);
        $attributes = $this->createAttributesString($attributes);
        if (!empty($attributes)) {
            $attributes = ' ' . $attributes;
        }

        // Flatten message array
        $escapeHtml      = $this->getEscapeHtmlHelper();
        $messagesToPrint = array();
        array_walk_recursive($messages, function ($item) use (&$messagesToPrint, $escapeHtml) {
            $messagesToPrint[] = $escapeHtml($item);
        });

        if (empty($messagesToPrint)) {
            return '';
        }

        // Generate markup
        $markup  = sprintf($this->getMessageOpenFormat(), $attributes);
        $markup .= implode($this->getMessageSeparatorString(), $messagesToPrint);
        $markup .= $this->getMessageCloseString();

        return $markup;
    }

}

It's just an extension of FormElementErrors with the render function overridden to include this:

// We only want a single message
$messages = array(current($messages));

I then insert the helper into my application using the solution I posted to my issue here.

Upvotes: 2

Related Questions