Commit db25f46e authored by romanb's avatar romanb

Finished the validation changes.

Ticket: 150
parent 42f7cb70
......@@ -244,6 +244,11 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$validator = new Doctrine_Validator();
$validator->validateRecord($this);
$this->validate();
if ($this->state == self::STATE_TDIRTY || $this->state == self::STATE_TCLEAN) {
$this->validateOnInsert();
} else {
$this->validateOnUpdate();
}
return $this->errorStack->count() == 0 ? true : false;
//$this->errorStack->merge($validator->getErrorStack());
......@@ -254,6 +259,18 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* validations that are neccessary.
*/
protected function validate() {}
/**
* Empty tempalte method to provide concrete Record classes with the possibility
* to hook into the validation procedure only when the record is going to be
* updated.
*/
protected function validateOnUpdate() {}
/**
* Empty tempalte method to provide concrete Record classes with the possibility
* to hook into the validation procedure only when the record is going to be
* inserted into the data store the first time.
*/
protected function validateOnInsert() {}
/**
* getErrorStack
*
......@@ -840,7 +857,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$conn = $this->table->getConnection();
}
$conn->beginTransaction();
$saveLater = $conn->saveRelated($this);
if ($this->isValid()) {
......
<?php
class Doctrine_Validator_Regexp {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
if(is_array($args)) {
foreach($args as $regexp) {
if( ! preg_match("/$args/", $value))
return false;
}
return true;
} else {
if(preg_match("/$args/", $value))
return true;
}
return false;
}
}
<?php
class Doctrine_Validator_Regexp {
/**
* @param Doctrine_Record $record
* @param string $key
* @param mixed $value
* @param string $args
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
if(is_array($args)) {
foreach($args as $regexp) {
if( ! preg_match($args, $value))
return false;
}
return true;
} else {
if(preg_match($args, $value))
return true;
}
return false;
}
}
......@@ -10,17 +10,19 @@ class User extends Doctrine_Record {
$this->hasColumn("email_id","integer");
$this->hasColumn("created","integer",11);
}
// Our own validation
protected function validate() {
if ($this->name == 'God') {
// Blasphemy! Stop that! ;-)
// syntax: add(<fieldName>, <error code/identifier>)
$this->errorStack->add('name', 'forbiddenName');
}
}
}
class Email extends Doctrine_Record {
public function setTableDefinition() {
// validators 'email' and 'unique' used
$this->hasColumn("address","string",150, array("email", "unique" => true));
}
protected function validate() {
if ($this->address !== 'the-only-allowed-mail@address.com') {
// syntax: add(<fieldName>, <error code>)
$this->errorStack->add('address', 'myCustomErrorCode');
}
$this->hasColumn("address","string",150, array("email", "unique"));
}
}
?>
......@@ -4,6 +4,8 @@ try {
$user->Email->address = "drink@@notvalid..";
$user->save();
} catch(Doctrine_Validator_Exception $e) {
// Note: you could also use $e->getInvalidRecords(). The direct way
// used here is just more simple when you know the records you're dealing with.
$userErrors = $user->getErrorStack();
$emailErrors = $user->Email->getErrorStack();
......
......@@ -14,10 +14,15 @@ a predefined validator you have three options:<br />
<br />
The first two options are advisable if it is likely that the validation is of general use
and is potentially applicable in many situations. In that case it is a good idea to implement
a new validator. However if the validation is special it is better to use hooks provided by Doctrine.
One of these hooks is the validate() method. If you need a special validation in your active record
you can simply override validate() in your active record class (a descendant of Doctrine_Record).
Within this method you can use all the power of PHP to validate your fields. When a field
a new validator. However if the validation is special it is better to use hooks provided by Doctrine:<br />
<br />
- validate() (Executed every time the record gets validated)<br />
- validateOnInsert() (Executed when the record is new and gets validated)<br />
- validateOnUpdate() (Executed when the record is not new and gets validated)<br />
<br />
If you need a special validation in your active record
you can simply override one of these methods in your active record class (a descendant of Doctrine_Record).
Within thess methods you can use all the power of PHP to validate your fields. When a field
doesnt pass your validation you can then add errors to the record's error stack.
The following code snippet shows an example of how to define validators together with custom
validation:<br />
......@@ -202,31 +202,67 @@ class Doctrine_ValidatorTestCase extends Doctrine_UnitTestCase {
}
/**
* Tests whether custom validation through template methods works correctly
* Tests whether the validate() callback works correctly
* in descendants of Doctrine_Record.
*/
public function testCustomValidation() {
public function testValidationHooks() {
$this->manager->setAttribute(Doctrine::ATTR_VLD, true);
$user = $this->connection->getTable("User")->find(4);
// Tests validate() and validateOnInsert()
$user = new User();
try {
$user->name = "I'm not The Saint";
$user->password = "1234";
$user->save();
} catch(Doctrine_Validator_Exception $e) {
$this->assertEqual($e->count(), 1);
$invalidRecords = $e->getInvalidRecords();
$this->assertEqual(count($invalidRecords), 1);
$stack = $invalidRecords[0]->getErrorStack();
$this->assertEqual($stack->count(), 2);
$this->assertTrue(in_array('notTheSaint', $stack['name'])); // validate() hook constraint
$this->assertTrue(in_array('pwNotTopSecret', $stack['password'])); // validateOnInsert() hook constraint
}
// Tests validateOnUpdate()
$user = $this->connection->getTable("User")->find(4);
try {
$user->name = "The Saint"; // Set correct name
$user->password = "Top Secret"; // Set correct password
$user->loginname = "Somebody"; // Wrong login name!
$user->save();
$this->fail();
} catch(Doctrine_Validator_Exception $e) {
$invalidRecords = $e->getInvalidRecords();
$this->assertEqual(count($invalidRecords), 1);
$stack = $invalidRecords[0]->getErrorStack();
$this->assertEqual($stack->count(), 1);
$this->assertTrue(in_array('notTheSaint', $stack['name']));
$this->assertTrue(in_array('notNobody', $stack['loginname'])); // validateOnUpdate() hook constraint
}
$this->manager->setAttribute(Doctrine::ATTR_VLD, false);
}
/**
* Tests whether the validateOnInsert() callback works correctly
* in descendants of Doctrine_Record.
*/
public function testHookValidateOnInsert() {
$this->manager->setAttribute(Doctrine::ATTR_VLD, true);
$user = new User();
$user->password = "1234";
try {
$user->name = "The Saint";
$user->save();
} catch(Doctrine_Validator_Exception $e) {
$this->fail();
} catch (Doctrine_Validator_Exception $ex) {
$errors = $user->getErrorStack();
$this->assertTrue(in_array('pwNotTopSecret', $errors['password']));
}
$this->manager->setAttribute(Doctrine::ATTR_VLD, false);
......
......@@ -9,7 +9,7 @@ class Entity extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("id","integer",20,"autoincrement|primary");
$this->hasColumn("name","string",50);
$this->hasColumn("loginname","string",20,"unique");
$this->hasColumn("loginname","string",20, array("unique"));
$this->hasColumn("password","string",16);
$this->hasColumn("type","integer",1);
$this->hasColumn("created","integer",11);
......@@ -104,6 +104,16 @@ class User extends Entity {
$this->errorStack->add('name', 'notTheSaint');
}
}
public function validateOnInsert() {
if ($this->password !== 'Top Secret') {
$this->errorStack->add('password', 'pwNotTopSecret');
}
}
public function validateOnUpdate() {
if ($this->loginname !== 'Nobody') {
$this->errorStack->add('loginname', 'notNobody');
}
}
}
class Groupuser extends Doctrine_Record {
public function setTableDefinition() {
......@@ -421,7 +431,7 @@ class ValidatorTest extends Doctrine_Record {
$this->hasColumn("myobject", "object", 1000);
$this->hasColumn("myinteger", "integer", 11);
$this->hasColumn("myrange", "integer", 11, array('range' => array(4,123)));
$this->hasColumn("myregexp", "string", 5, array('regexp' => '^[0-9]+$'));
$this->hasColumn("myregexp", "string", 5, array('regexp' => '/^[0-9]+$/'));
$this->hasColumn("myemail", "string", 100, "email");
$this->hasColumn("myemail2", "string", 100, "email|notblank");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment