Globally change Zend form errors in zf2

Hi there,

I’m currently setting up some forms using Zend. I’m using the FormFilter class to validate the forms.

The default error messages are pretty dry, so I’d like to make them more readable.

The problem is that I have over 13 forms, and with 4 or 5 inputs on each form, I don’t really want to have to set the error message per input. This stock overflow post seemed useful (http://stackoverflow.com/questions/459921/zend-form-nicely-change-setrequired-validate-message), but I’m guessing its based on zf1, because some of the classes don’t seem to be present, or have changed.

In fact I have found that whenever I call a call with Zend as a prefix, like Zend_Validate_Abstract, I get an error message telling me the class does not exists. I have to call it like so: Zend\Validator\AbstractValidator.

I’m not sure if this is the best method of doing things in Zend, but its the method they used in the tutorials on their site.

Any help would be greatly appreciated.

Best,
M

Hi Mike,

I’m not 100% certain, but I think you could replace the default validation messages by editing the language translation file.

Check this manual page for more details: http://framework.zend.com/manual/2.0/en/modules/zend.validator.messages.html

Edit: Reading through the Stack Overflow question you linked to, I see one of the answers (by John B) makes a similar suggestion. Perhaps the manual page will enable you to update the code to work with ZF2.

Yep John B’s answer looks ideal:


$translateValidators = array(
        				Zend_Validate_NotEmpty::IS_EMPTY => 'Value must be entered',
        				Zend_Validate_Regex::NOT_MATCH => 'Invalid value entered',
        				Zend_Validate_StringLength::TOO_SHORT => 'Value cannot be less than %min% characters',
        				Zend_Validate_StringLength::TOO_LONG => 'Value cannot be longer than %max% characters',
        				Zend_Validate_EmailAddress::INVALID => 'Invalid e-mail address'
        			);
    $translator = new Zend_Translate('array', $translateValidators);
    Zend_Validate_Abstract::setDefaultTranslator($translator);

Except when I drop it into the onBootstrap method in myZendApp/module/Application/Module.php, I get the following error message:
‘Application\Zend_Validate_NotEmpty’ not found in myZendApp/module/Application/Module.php on line 28

I can reference the classes directly, like so:


$translateValidators = array(
        				\\Zend\\Validator\\NotEmpty::IS_EMPTY => 'Value must be entered',
        				\\Zend\\Validator\\Regex::NOT_MATCH => 'Invalid value entered',
        				\\Zend\\Validator\\StringLength::TOO_SHORT => 'Value cannot be less than %min% characters',
        				\\Zend\\Validator\\StringLength::TOO_LONG => 'Value cannot be longer than %max% characters',
        				\\Zend\\Validator\\EmailAddress::INVALID => 'Invalid e-mail address'
        			);

which will get me the correct constants… However the closest thing to Zend_Translate I can find is Zend\Validator\Translator\TranslatorInterface:


/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
 * @license   http://framework.zend.com/license/new-bsd New BSD License
 */

namespace Zend\\Validator\\Translator;

interface TranslatorInterface
{
    /**
     * @param  string $message
     * @param  string $textDomain
     * @param  string $locale
     * @return string
     */
    public function translate($message, $textDomain = 'default', $locale = null);
}

which isn’t very useful in this instance.

Anyway, I’ll keep digging…

What about if you edit the messages in /resources/languages/en/Zend_Validate.php and then use this code from the manual page:


$translator = new Zend\\I18n\\Translator\\Translator();
$translator->addTranslationFile(
    'phpArray'
    '/resources/languages/en/Zend_Validate.php',
    'default',
    'en_US'
);
Zend\\Validator\\AbstractValidator::setDefaultTranslator($translator);

Note that you might have to change the path to Zend_Validate.php, depending on your setup.

OK, I’ve done a little more browsing through the API docs, and it looks like you may be able to do this:


$messages = array(
    'Value must be entered' => \\Zend\\Validator\\NotEmpty::IS_EMPTY,
    'Invalid value entered' => \\Zend\\Validator\\Regex::NOT_MATCH,
    'Value cannot be less than %min% characters' => \\Zend\\Validator\\StringLength::TOO_SHORT,
    'Value cannot be longer than %max% characters' => \\Zend\\Validator\\StringLength::TOO_LONG,
    'Invalid e-mail address' => \\Zend\\Validator\\NotEmpty::IS_EMPTY
);

Zend\\Validator\\AbstractValidator::setMessages($messages);

which would be simpler.

Edit: I’ve altered the above example, as the keys and values have to be reversed.

Cheers fretburner,

I’ve added your code snippet to the onBootstrapper method, and I get the following error message:
Fatal error: Call to undefined method Application\Module::setMessage() in /path/to/Zend/Validator/AbstractValidator.php on line 229

here’s the method in full:


public function onBootstrap(MvcEvent $e)
{
    $eventManager = $e->getApplication()->getEventManager();
    $moduleRouteListener = new ModuleRouteListener();
    $moduleRouteListener->attach($eventManager);

    $messages = array(
        'Value must be entered' => Validator\\NotEmpty::IS_EMPTY,
        'Invalid value entered' => Validator\\Regex::NOT_MATCH,
        'Value cannot be less than %min% characters' => Validator\\StringLength::TOO_SHORT,
        'Value cannot be longer than %max% characters' => Validator\\StringLength::TOO_LONG,
        'Invalid e-mail address' => Validator\\NotEmpty::IS_EMPTY
    );

    Validator\\AbstractValidator::setMessages($messages);
}

I notice that Zend\Validator\AbstractValidator::setMessages() is trying to call a setMessage method in the above Module class.

I’m guessing setMessages() needs to be called from within a different class?

Doh, my bad I’m afraid! setMessages isn’t a static method, so it needs to be called on an instance of the class.

Have you tried my previous suggestion of updating the translation file?

Yep, I get:
Catchable fatal error: Argument 1 passed to Zend\Validator\AbstractValidator::setDefaultTranslator() must be an instance of Zend\Validator\Translator\TranslatorInterface, instance of Zend\I18n\Translator\Translator given

I tried changing the $translator to an instance of Zend\Validator\Translator\TranslatorInterface, but got the following error:
Fatal error: Cannot instantiate interface Zend\Validator\Translator\TranslatorInterface

The __construct method needs to be passed a few variables:


<?php
/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
 * @license   http://framework.zend.com/license/new-bsd New BSD License
 */

namespace Zend\\Validator\\Translator;

interface TranslatorInterface
{
    /**
     * @param  string $message
     * @param  string $textDomain
     * @param  string $locale
     * @return string
     */
    public function translate($message, $textDomain = 'default', $locale = null);
}

Not sure where to go from here.

OK, so I’ve downloaded the ZF getting started app, and I tried this:


public function onBootstrap(MvcEvent $e) 
{ 
    $eventManager = $e->getApplication()->getEventManager(); 
    $moduleRouteListener = new ModuleRouteListener(); 
    $moduleRouteListener->attach($eventManager); 

    $translator = $e->getApplication()->getServiceManager()->get('translator');
    $translator->addTranslationFile( 
        'phpArray', 
        'vendor/zendframework/zendframework/resources/languages/en/Zend_Validate.php', 
        'default', 
        'en_US' 
    ); 
    \\Zend\\Validator\\AbstractValidator::setDefaultTranslator($translator); 
}

It doesn’t throw any errors, but I don’t know if it actually translates the messages or not either as I don’t have a form setup, but it looks like it might be worth a try.

YEAH!!

Muito obrigado fretburner!

:slight_smile: