Commit a9ccd9dc authored by doctrine's avatar doctrine

Validator: support for array and object types, better handling of null valued columns

parent d1ed73c6
......@@ -131,6 +131,7 @@ class Doctrine_DBStatement extends PDOStatement {
*/
public function execute(array $params = null) {
$time = microtime();
$result = parent::execute($params);
$exectime = (microtime() - $time);
......
......@@ -41,6 +41,7 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
Doctrine_Record::initNullObject($this->null);
Doctrine_Collection::initNullObject($this->null);
Doctrine_Record_Iterator::initNullObject($this->null);
Doctrine_Validator::initNullObject($this->null);
}
/**
* @return Doctrine_Null
......
......@@ -98,8 +98,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
*/
private static $index = 1;
/**
* @var Doctrine_Null $nullObject a Doctrine_Null object used for extremely fast
* SQL null value testing
* @var Doctrine_Null $null a Doctrine_Null object used for extremely fast
* null value testing
*/
private static $null;
/**
......@@ -208,10 +208,12 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* modifies data array
* example:
*
* $data = array("name"=>"John","lastname"=> null,"id"=>1,"unknown"=>"unknown");
* $names = array("name","lastname","id");
* $data = array("name"=>"John","lastname"=> null, "id" => 1,"unknown" => "unknown");
* $names = array("name", "lastname", "id");
* $data after operation:
* $data = array("name"=>"John","lastname" => array(),"id"=>1);
* $data = array("name"=>"John","lastname" => Object(Doctrine_Null));
*
* here column 'id' is removed since its auto-incremented primary key (protected)
*/
private function cleanData() {
$tmp = $this->data;
......@@ -219,14 +221,21 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->data = array();
foreach($this->table->getColumnNames() as $name) {
$type = $this->table->getTypeOf($name);
if( ! isset($tmp[$name])) {
$this->data[$name] = self::$null;
if($type == 'array') {
$this->data[$name] = array();
$this->modified[] = $name;
} else
$this->data[$name] = self::$null;
} else {
switch($this->table->getTypeOf($name)):
switch($type):
case "array":
case "object":
if($tmp[$name] !== self::$null)
$this->data[$name] = unserialize($tmp[$name]);
break;
default:
$this->data[$name] = $tmp[$name];
......@@ -235,8 +244,9 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
}
/**
* prepares identifiers
* prepares identifiers for later use
*
* @param boolean $exists whether or not this record exists in persistent data store
* @return void
*/
private function prepareIdentifiers($exists = true) {
......@@ -706,9 +716,9 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
foreach($this->modified as $k => $v) {
$type = $this->table->getTypeOf($v);
if($type == 'array' ||
$type == 'object') {
$type == 'object') {
$a[$v] = serialize($this->data[$v]);
continue;
......
......@@ -747,7 +747,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
* @return boolean
*/
private function update(Doctrine_Record $record) {
$array = $record->getModified();
$array = $record->getPrepared();
if(empty($array))
return false;
......
......@@ -31,7 +31,7 @@ class Doctrine_Validator {
/**
* constant for blank validation error
*/
const ERR_BLANK = 4;
const ERR_NOTBLANK = 4;
/**
* constant for date validation error
*/
......@@ -39,7 +39,7 @@ class Doctrine_Validator {
/**
* constant for null validation error
*/
const ERR_NULL = 6;
const ERR_NOTNULL = 6;
/**
* constant for enum validation error
*/
......@@ -53,13 +53,27 @@ class Doctrine_Validator {
/**
* @var array $stack error stack
* @var array $stack error stack
*/
private $stack = array();
/**
* @var array $validators an array of validator objects
* @var array $validators an array of validator objects
*/
private static $validators = array();
/**
* @var Doctrine_Null $null a Doctrine_Null object used for extremely fast
* null value testing
*/
private static $null;
/**
* initNullObject
*
* @param Doctrine_Null $null
* @return void
*/
public static function initNullObject(Doctrine_Null $null) {
self::$null = $null;
}
/**
* returns a validator object
*
......@@ -86,21 +100,32 @@ class Doctrine_Validator {
* @return void
*/
public function validateRecord(Doctrine_Record $record) {
$modified = $record->getModified();
$columns = $record->getTable()->getColumns();
$name = $record->getTable()->getComponentName();
switch($record->getState()):
case Doctrine_Record::STATE_TDIRTY:
case Doctrine_Record::STATE_TCLEAN:
$data = $record->getData();
break;
default:
$data = $record->getModified();
endswitch;
$err = array();
foreach($modified as $key => $value) {
foreach($data as $key => $value) {
if($value === self::$null)
$value = null;
$column = $columns[$key];
if(strlen($value) > $column[1]) {
$err[$key] = Doctrine_Validator::ERR_LENGTH;
continue;
if($column[0] == 'array' || $column[0] == 'object') {
$value = serialize($value);
}
if(self::gettype($value) !== $column[0]) {
$err[$key] = Doctrine_Validator::ERR_TYPE;
if(strlen($value) > $column[1]) {
$err[$key] = Doctrine_Validator::ERR_LENGTH;
continue;
}
......@@ -116,28 +141,22 @@ class Doctrine_Validator {
$validator = self::getValidator($args[0]);
if( ! $validator->validate($record, $key, $value, $args[1])) {
switch(strtolower($args[0])):
case "unique":
$err[$key] = Doctrine_Validator::ERR_UNIQUE;
break;
case "notnull":
$err[$key] = Doctrine_Validator::ERR_NULL;
break;
case "notblank":
$err[$key] = Doctrine_Validator::ERR_BLANK;
break;
case "enum":
$err[$key] = Doctrine_Validator::ERR_VALID;
break;
default:
$err[$key] = Doctrine_Validator::ERR_VALID;
break;
endswitch;
}
// errors found quit validation looping for this column
if(isset($err[$key]))
$constant = 'Doctrine_Validator::ERR_'.strtoupper($args[0]);
if(defined($constant))
$err[$key] = constant($constant);
else
$err[$key] = Doctrine_Validator::ERR_VALID;
// errors found quit validation looping for this column
break;
}
}
if(self::gettype($value) !== $column[0] && self::gettype($value) != 'NULL') {
$err[$key] = Doctrine_Validator::ERR_TYPE;
continue;
}
}
......
<?php
class Doctrine_ValidatorTestCase extends Doctrine_UnitTestCase {
public function prepareTables() {
$this->tables[] = "Validator_Test";
parent::prepareTables();
}
public function testValidate2() {
$test = new Validator_Test();
$test->mymixed = "message";
$validator = new Doctrine_Validator();
$validator->validateRecord($test);
$stack = $validator->getErrorStack();
$this->assertTrue(is_array($stack));
$stack = $stack['Validator_Test'][0];
$this->assertEqual($stack['mystring'], Doctrine_Validator::ERR_NOTNULL);
$test->mystring = 'str';
$test->save();
}
public function testValidate() {
$user = $this->session->getTable("User")->find(4);
......@@ -71,6 +93,5 @@ class Doctrine_ValidatorTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($a["User"][0]["name"], Doctrine_Validator::ERR_LENGTH);
$this->manager->setAttribute(Doctrine::ATTR_VLD, false);
}
}
?>
......@@ -313,4 +313,13 @@ class Log_Status extends Doctrine_Record {
$this->hasColumn("name", "string", 255);
}
}
class Validator_Test extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("mymixed","string", 100);
$this->hasColumn("mystring","string", 100, "notnull|unique");
$this->hasColumn("myarray", "array", 1000);
$this->hasColumn("myobject", "object", 1000);
$this->hasColumn("myinteger", "integer", 11);
}
}
?>
......@@ -15,7 +15,6 @@ require_once("CollectionTestCase.php");
require_once("CacheSqliteTestCase.php");
require_once("CollectionOffsetTestCase.php");
require_once("SenseiTestCase.php");
require_once("QueryTestCase.php");
error_reporting(E_ALL);
......
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