Error handling with Extbase: Set own error messages

Ever tried to make a complex form with Extbase and Fluid and had troubles with not knowing how to properly handle errors? I did, and to make life more easy for everybody I let you know my solutions.

In this first part of my series I write about setting own error messages instead of using the system ones. Ready? Here we go!

How to set own error messages?

At first we need to know when errors occur. That’s quite easy because there are just two cases:

  1. Using annotations to validate model properties against one single rule
  2. Using your own validator class for more complex validation.

So, when validating your model properties with annotations you can either use all the validators Extbase has on board or write your own ones. In case you want to verify an email-address it makes sense using the built-in validator because it provides a nice regular expression you probably not want to write again. Let’s see some code:

class Tx_ExtensionName_Domain_Model_ModelName extends Tx_Extbase_DomainObject_AbstractEntity
{
    /**
     * @var string
     * @validate Tx_Extbase_Validation_Validator_EmailAddressValidator
     */
    protected $email= '';
}

This part is your own model with an email property you want to validate.

class Tx_Extbase_Validation_Validator_EmailAddressValidator extends Tx_Extbase_Validation_Validator_AbstractValidator {

	public function isValid($value) {
		$this->errors = array();
		if(is_string($value) && preg_match('
				/
					^[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+\/=?^_`{|}~-]+)*
					@
					(?:
						(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[a-z]{2}|aero|asia|biz|cat|com|edu|coop|gov|info|int|invalid|jobs|localdomain|mil|mobi|museum|name|net|org|pro|tel|travel)|
						localhost|
						(?:(?:\d{1,2}|1\d{1,2}|2[0-5][0-5])\.){3}(?:(?:\d{1,2}|1\d{1,2}|2[0-5][0-5]))
					)
					\b
				/ix', $value)) return TRUE;
		$this->addError('The given subject was not a valid email address.', 1221559976);
		return FALSE;
	}
}

And this one is the given validator class.

Now, when using this validator, it causes the standard error message “The given subject was not a valid email address.“. Either you simply want to change the message to sth. more fitting like “Sorry dude, please enter a valid email address” or translate it into another language there’s the same easy solution for both cases: The Fluid translation tag.

Btw. you should have a look at the blog_example. Most of my knowledge I do have from this extension.

<f:translate key="LLL:EXT:extension/Resources/Private/Language/locallang.xml:key" />

There’s also the possibility to use this tag “inline” but it’s not that important in this blog post. Nevertheless you should have a look at it as most Fluid tags can be used this way.

<img alt="{f:translate(key:'LLL:EXT:p/a/t/h/locallang.xml:key')}" />

Before showing you the template with it’s error part and how to actually combine it with the translation tags, I need your attention because the way you access errors is a bit special and worth being explained in a few sentences. Here we go:

In your template you can access all occurring errors through one object of type Tx_Extbase_MVC_Controller_ArgumentError. Let’s say you have ten properties to validate and all of them produce an error, than your error object contains an array of ten objects of type Tx_Extbase_Validation_PropertyError inside. Each of these objects also has an array to store multiple objects of type Tx_Extbase_Validation_Error.

Does not make sense? It does! While the first array contains all the Tx_Extbase_Validation_PropertyError objects for each property that threw an error, the second array inside the Tx_Extbase_Validation_PropertyError object contains all Tx_Extbase_Validation_Error objects related to the property itself. Still not clear?

Imagine you have more than one validation rule for a property. Perhaps you want an email address to be valid and unique inside your system environment, then you have to validate against two validation rules that can throw an error message each. For a better understanding here is a visualisation of it:

Tx_Extbase_MVC_Controller_ArgumentError Object
(
    [message:protected] => Validation errors for argument "newObject"
    [code:protected] => 1245107351
    [propertyName:protected] => newObject
    [errors:protected] => Array
        (
            [email] => Tx_Extbase_Validation_PropertyError Object
                (
                    [message:protected] => Validation errors for property "email"
                    [code:protected] => 1242859509
                    [propertyName:protected] => email
                    [errors:protected] => Array
                        (
                            [0] => Tx_Extbase_Validation_Error Object
                                (
                                    [message:protected] => The given subject was not a valid email address.
                                    [code:protected] => 1221559976
                                )
                            [1] => Tx_Extbase_Validation_Error Object
                                (
                                    [message:protected] => The email address is not unique.
                                    [code:protected] => 1221559989
                                )
                        )
                )
	)
)

In the following code I just iterate through the error array of a single Tx_Extbase_Validation_PropertyError object while property.errors is the error array.

<ul>
<f:for each="{property.errors}" as="propertyError">
    <li>
        {propertyError.message}
    </li>
</f:for>
</ul>

Now there's not much more to do or understand. Instead of showing the original error message we use a translation tag.

<ul>
<f:for each="{property.errors}" as="propertyError">
    <li>
        <f:translate key="error.{property.propertyName}" htmlEscape="false">Not translated: [{propertyError.message}]</f:translate>
    </li>
</f:for>
</ul>

So we can easily access our desired/translated error message. The corresponding locallang.xml should look like this:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3locallang>
    <meta type="array">
        <type>module</type>
        <description>Language labels for the extension</description>
    </meta>
    <data type="array">
        <languageKey index="default" type="array">
            <label index="error.email">your error message</label>
        </languageKey>
    </data>
</T3locallang>

Be free to experience what else is possible or necessary. If you want to have more than one error message translated I recommend you to extend the locallang key with the error code. Could be sth. like this:

<f:translate key="error.{field.propertyName}.{field.errorCode}" htmlEscape="false">Not translated: [{fieldError.message}]</f:translate>
<label index="error.email.1221559976">your error message</label>

Alright, that's it in the first place. Here is a list of all links I referred to in this post.

Useful links:

 

Found a mistake? Have a question? Offer critisism?
Just leave a reply!

One Response to Error handling with Extbase: Set own error messages

  1. Alex says:

    Hi alex,
    thanks for this nice tutorial.
    I found a small problem at the end of you article.
    <f:translate key="error.{field.propertyName}.{field.errorCode}" ... This will only work if your property is lowercase only. If you use lower-camelcase like myTestProperty it won’t work because you will have to convert it to my_test_property. Did you have any solution for this?

    Thanks
    Alex

Leave a Reply

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

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>