tags:

views:

382

answers:

2

I need to modify default error messages of doctrine validations. How can I do this?

thanks

A: 

Its not possible in current version!!!

CrazyJoe
It's good to know, thanks
inakiabt
ok, thanks for your answer
rizidoro
+2  A: 

Hi,

CrazyJoe is right, in a way : it is not possible without some hard work :-(

But, if you search hard enough, you might find a way ;-)


With Doctrine 1.1, you model classes extend Doctrine_Record.
That class defines this method :

/**
 * Get the record error stack as a human readable string.
 * Useful for outputting errors to user via web browser
 *
 * @return string $message
 */
public function getErrorStackAsString()
{
    $errorStack = $this->getErrorStack();

    if (count($errorStack)) {
        $message = sprintf("Validation failed in class %s\n\n", get_class($this));

        $message .= "  " . count($errorStack) . " field" . (count($errorStack) > 1 ?  's' : null) . " had validation error" . (count($errorStack) > 1 ?  's' : null) . ":\n\n";
        foreach ($errorStack as $field => $errors) {
            $message .= "    * " . count($errors) . " validator" . (count($errors) > 1 ?  's' : null) . " failed on $field (" . implode(", ", $errors) . ")\n";
        }
        return $message;
    } else {
        return false;
    }
}

This is the method that generates the messages ; as you can see, it's fully automatic, and not configurable at all :-(


Still, thanks to OOP, we can overload that method in our Model classes...

But, to be a bit cleaner, I would :

  • Create a new class -- say My_Doctrine_Record, that extends Doctrine_Record
  • That class would redefine that method, to allow customization of error messages
  • And our Model classes would extend that My_Doctrine_Record class.

This will avoid duplication of that method inside each of our model classes ; and might prove useful another day...


Our My_Doctrine_Record::getErrorStackAsString method can, of course, rely on a method of our model classes, to help generate the messages, with special customization for each model class.

Here's a working example ; far from perfect, but it might guide you to what you want to get ;-)


First of all, the initialisations :

require_once '/usr/share/php/Doctrine/lib/Doctrine.php';
spl_autoload_register(array('Doctrine', 'autoload'));

$manager = Doctrine_Manager::getInstance();
$manager->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL);

$conn = Doctrine_Manager::connection('mysql://test:123456@localhost/test1');

I'm guessing you already have something like that in your application...


Next, our new My_Doctrine_Record class :

class My_Doctrine_Record extends Doctrine_Record
{
    public function getErrorStackAsString()
    {
        $errorStack = $this->getErrorStack();
        if (count($errorStack)) {
            $message = sprintf("BAD DATA in class %s :\n", get_class($this));
            foreach ($errorStack as $field => $errors) {
                $messageForField = $this->_getValidationFailed($field, $errors);
                if ($messageForField === null) {
                    // No custom message for this case => we use the default one.
                    $message .= "    * " . count($errors) . " validator" . (count($errors) > 1 ?  's' : null) . " failed on $field (" . implode(", ", $errors) . ")\n";
                } else {
                    $message .= "    * " . $messageForField;
                }
            }
            return $message;
        } else {
            return false;
        }
    }

    protected function _getValidationFailed($field, $errors) {
        return null;
    }

}

You'll notice that the getErrorStackAsString method is inspired by what is done by the one provided by Doctrine -- this seems normal, I'd say ^^

One other thing to be noticed :

  • It defines and calls the _getValidationFailed method
  • that one should create error messages ; or return null if we want to use the default behabiour
  • and we can overload that _getValidationFailed method in our Model classes, to customize stuff ;-)


And now, my Model class :

class Test extends My_Doctrine_Record
{
    protected function _getValidationFailed($field, $errors) {
        switch ($field) {
            case 'name': 
                    return "You entered wrong data from 'name' field.\n      Errors are for '" 
                        . implode("', '", $errors) . "'\n";
                break;
            // other fields ?
            default:
                return null;
        }
    }

    public function setTableDefinition()
    {
        $this->setTableName('test');
        $this->hasColumn('id', 'integer', 4, array(
             'type' => 'integer',
             'length' => 4,
             'unsigned' => 0,
             'primary' => true,
             'autoincrement' => true,
             ));
        $this->hasColumn('name', 'string', 32, array(
             'type' => 'string',
             'length' => 32,
             'fixed' => false,
             'notnull' => true,
             'email'   => true,
             ));
        $this->hasColumn('value', 'string', 128, array(
             'type' => 'string',
             'length' => 128,
             'fixed' => false,
             'notnull' => true,
             'htmlcolor' => true,
             ));
        $this->hasColumn('date_field', 'integer', 4, array(
             'type' => 'timestamp',
             'notnull' => true,
             ));
    }
}

It extends My_Doctrine_Record, and defines a _getValidationFailed method, that deals with validations errors on the name field of my model.


Now, let's suppose I do that to load a record :

$test = Doctrine::getTable('Test')->find(1);
var_dump($test->toArray());

Let's try to modify it, setting up "bad" values :

$test->name = (string)time();
$test->value = 'glop';
try {
    $test->save();
} catch (Doctrine_Validator_Exception $e) {
    echo '<pre>';
    echo $e->getMessage();
    echo '</pre>';
    die;
}

Both name and value fields are not OK... So, we'll go through our validations methods, and generate this error message :

BAD DATA in class Test :
    * You entered wrong data from 'name' field.
      Errors are for 'email'
    * 1 validator failed on value (htmlcolor)

You can see the message for "name" has been customized, and the one for "value" comes from the default Doctrine thing.


So, to conclude : not easy, but do-able ;-)

And, now, it's up to you to use this as a guide to the exact solution to your problem :-)
It will need some more coding, I think... But you're not far away from the real deal !

Have fun !

Pascal MARTIN