From 4cd29eaf2c3851a7a4d88b267da14b9ae38cf250 Mon Sep 17 00:00:00 2001 From: zYne Date: Thu, 26 Oct 2006 20:53:59 +0000 Subject: [PATCH] DQL enum handling fixed, fixes #202 --- lib/Doctrine/Query/Where.php | 78 +++++++++++++++++++-------- lib/Doctrine/Relation/Association.php | 9 ++-- lib/Doctrine/Table.php | 34 +++++------- tests/EnumTestCase.php | 21 +++++--- tests/run.php | 8 ++- 5 files changed, 94 insertions(+), 56 deletions(-) diff --git a/lib/Doctrine/Query/Where.php b/lib/Doctrine/Query/Where.php index 8af7161d9..4edce7163 100644 --- a/lib/Doctrine/Query/Where.php +++ b/lib/Doctrine/Query/Where.php @@ -28,7 +28,7 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition { } $r = array_shift($e); - $a = explode(".",$r); + $a = explode('.', $r); if(count($a) > 1) { $field = array_pop($a); @@ -84,36 +84,43 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition { } } else { $table = $this->query->load($reference, false); - $enumIndex = $table->enumIndex($field, trim($value,"'")); $alias = $this->query->getTableAlias($reference); $table = $this->query->getTable($alias); + // check if value is enumerated value + $enumIndex = $table->enumIndex($field, trim($value, "'")); + if(substr($value, 0, 1) == '(') { + // trim brackets + $trimmed = Doctrine_Query::bracketTrim($value); - if($value == 'true') - $value = 1; - elseif($value == 'false') - $value = 0; - elseif(substr($value,0,5) == '(FROM') { - // subquery - $sub = Doctrine_Query::bracketTrim($value); - $q = new Doctrine_Query(); - $value = '(' . $q->parseQuery($sub)->getQuery() . ')'; - } else { - // check that value isn't a string - if(strpos($value, '\'') === false) { - $a = explode('.', $value); - - if(count($a) > 1) { - // either a float or a component.. - - if( ! is_numeric($a[0])) { - // a component found - $value = $this->query->getTableAlias($a[0]). '.' . $a[1]; - } + if(substr($trimmed, 0, 4) == 'FROM' || substr($trimmed, 0, 6) == 'SELECT') { + // subquery found + $q = new Doctrine_Query(); + $value = '(' . $q->parseQuery($trimmed)->getQuery() . ')'; + } elseif(substr($trimmed, 0, 4) == 'SQL:') { + $value = '(' . substr($trimmed, 4) . ')'; + } else { + // simple in expression found + $e = Doctrine_Query::sqlExplode($trimmed, ','); + + $value = array(); + foreach($e as $part) { + $index = $table->enumIndex($field, trim($part, "'")); + if($index !== false) + $value[] = $index; + else + $value[] = $this->parseLiteralValue($part); } + $value = '(' . implode(', ', $value) . ')'; } + } else { + if($enumIndex !== false) + $value = $enumIndex; + else + $value = $this->parseLiteralValue($value); } + switch($operator) { case '<': case '>': @@ -128,7 +135,32 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition { } return $where; } + public function parseLiteralValue($value) { + // check that value isn't a string + if(strpos($value, '\'') === false) { + + // parse booleans + if($value == 'true') + $value = 1; + elseif($value == 'false') + $value = 0; + $a = explode('.', $value); + + if(count($a) > 1) { + // either a float or a component.. + + if( ! is_numeric($a[0])) { + // a component found + $value = $this->query->getTableAlias($a[0]). '.' . $a[1]; + } + } + } else { + // string literal found + } + + return $value; + } public function parseExists($where, $negation) { $operator = ($negation) ? 'EXISTS' : 'NOT EXISTS'; diff --git a/lib/Doctrine/Relation/Association.php b/lib/Doctrine/Relation/Association.php index b3daa21dd..bfce9664e 100644 --- a/lib/Doctrine/Relation/Association.php +++ b/lib/Doctrine/Relation/Association.php @@ -61,10 +61,11 @@ class Doctrine_Relation_Association extends Doctrine_Relation { public function getRelationDql($count, $context = 'record') { switch($context): case "record": - $sub = "SELECT ".$this->foreign. - " FROM ".$this->associationTable->getTableName(). - " WHERE ".$this->local. - " IN (".substr(str_repeat("?, ", $count),0,-2).")"; + $sub = 'SQL:SELECT ' . $this->foreign. + ' FROM ' . $this->associationTable->getTableName(). + ' WHERE ' . $this->local. + ' IN (' . substr(str_repeat("?, ", $count),0,-2) . + ')'; $dql = "FROM ".$this->table->getComponentName(); $dql .= ".".$this->associationTable->getComponentName(); diff --git a/lib/Doctrine/Table.php b/lib/Doctrine/Table.php index eb7fb94a6..550233ff3 100644 --- a/lib/Doctrine/Table.php +++ b/lib/Doctrine/Table.php @@ -88,8 +88,8 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable { * * so the full columns array might look something like the following: * array( - * 'name' => array('string', 20, array('notnull' => true, 'default' => 'someone') - * 'age' => array('integer', 11, array('notnull' => true)) + * 'name' => array('string', 20, array('notnull' => true, 'default' => 'someone')), + * 'age' => array('integer', 11, array('notnull' => true)) * ) */ protected $columns = array(); @@ -115,21 +115,21 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable { */ private $hasDefaultValues; /** - * @var array $options an array containing all options + * @var array $options an array containing all options * - * -- name name of the component, for example component name of the GroupTable is 'Group' + * -- name name of the component, for example component name of the GroupTable is 'Group' * - * -- tableName database table name, in most cases this is the same as component name but in some cases - * where one-table-multi-class inheritance is used this will be the name of the inherited table + * -- tableName database table name, in most cases this is the same as component name but in some cases + * where one-table-multi-class inheritance is used this will be the name of the inherited table * - * -- sequenceName Some databases need sequences instead of auto incrementation primary keys, - * you can set specific sequence for your table by calling setOption('sequenceName', $seqName) - * where $seqName is the name of the desired sequence + * -- sequenceName Some databases need sequences instead of auto incrementation primary keys, + * you can set specific sequence for your table by calling setOption('sequenceName', $seqName) + * where $seqName is the name of the desired sequence * - * -- enumMap enum value arrays + * -- enumMap enum value arrays * - * -- inheritanceMap inheritanceMap is used for inheritance mapping, keys representing columns and values - * the column values that should correspond to child classes + * -- inheritanceMap inheritanceMap is used for inheritance mapping, keys representing columns and values + * the column values that should correspond to child classes */ protected $options = array('name' => null, 'tableName' => null, @@ -484,7 +484,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable { public function getBoundForName($name, $component) { foreach($this->bound as $k => $bound) { $e = explode('.', $bound[0]); - + if($bound[3] == $name && $e[0] == $component) { return $this->bound[$k]; } @@ -873,7 +873,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable { /** * @param $id database row id * @throws Doctrine_Find_Exception - * @return DAOProxy a proxy for given identifier */ final public function getProxy($id = null) { if($id !== null) { @@ -889,13 +888,6 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable { } return $this->getRecord(); } - /** - * getTableDescription - * @return array - */ - final public function getTableDescription() { - return $this->columns; - } /** * count * diff --git a/tests/EnumTestCase.php b/tests/EnumTestCase.php index 580c57f4a..cef422d8c 100644 --- a/tests/EnumTestCase.php +++ b/tests/EnumTestCase.php @@ -22,7 +22,7 @@ class Doctrine_EnumTestCase extends Doctrine_UnitTestCase { try { $query = new Doctrine_Query($this->connection); - $ret = $query->query('FROM EnumTest WHERE EnumTest.status = open'); + $ret = $query->query("FROM EnumTest WHERE EnumTest.status = 'open'"); $this->assertEqual(count($ret), 1); } catch (Exception $e) { $this->fail(); @@ -32,7 +32,7 @@ class Doctrine_EnumTestCase extends Doctrine_UnitTestCase { public function testInAndNotIn() { try { $query = new Doctrine_Query($this->connection); - $ret = $query->query('FROM EnumTest WHERE EnumTest.status IN (open)'); + $ret = $query->query("FROM EnumTest WHERE EnumTest.status IN ('open')"); $this->assertEqual(count($ret), 1); } catch (Exception $e) { $this->fail(); @@ -40,18 +40,26 @@ class Doctrine_EnumTestCase extends Doctrine_UnitTestCase { try { $query = new Doctrine_Query($this->connection); - $ret = $query->query('FROM EnumTest WHERE EnumTest.status NOT IN (verified, closed)'); + $ret = $query->query("FROM EnumTest WHERE EnumTest.status NOT IN ('verified', 'closed')"); $this->assertEqual(count($ret), 1); } catch (Exception $e) { $this->fail(); } } - public function testNotEqual() - { + public function testExpressionComposition() { try { $query = new Doctrine_Query($this->connection); - $ret = $query->query('FROM EnumTest WHERE EnumTest.status != closed'); + $ret = $query->query("FROM EnumTest e WHERE e.id > 0 AND (e.status != 'closed' OR e.status = 'verified')"); + $this->assertEqual(count($ret), 1); + } catch (Exception $e) { + $this->fail(); + } + } + public function testNotEqual() { + try { + $query = new Doctrine_Query($this->connection); + $ret = $query->query("FROM EnumTest WHERE EnumTest.status != 'closed'"); $this->assertEqual(count($ret), 1); } catch (Exception $e) { $this->fail(); @@ -119,5 +127,6 @@ class Doctrine_EnumTestCase extends Doctrine_UnitTestCase { } $this->assertTrue($f); } + } ?> diff --git a/tests/run.php b/tests/run.php index ac7f5919d..ff75c8d26 100644 --- a/tests/run.php +++ b/tests/run.php @@ -54,6 +54,9 @@ require_once('BooleanTestCase.php'); require_once('EnumTestCase.php'); require_once('DataDictSqliteTestCase.php'); +require_once('DataDict/PgsqlTestCase.php'); + + require_once('CustomResultSetOrderTestCase.php'); error_reporting(E_ALL); @@ -61,6 +64,7 @@ print '
';
 
 $test = new GroupTest('Doctrine Framework Unit Tests');
 
+$test->addTestCase(new Doctrine_DataDict_Pgsql_TestCase());
 
 $test->addTestCase(new Doctrine_Relation_TestCase());
 
@@ -124,8 +128,6 @@ $test->addTestCase(new Doctrine_CustomResultSetOrderTestCase());
 
 $test->addTestCase(new Doctrine_BooleanTestCase());
 
-$test->addTestCase(new Doctrine_EnumTestCase());
-
 $test->addTestCase(new Doctrine_Record_Filter_TestCase());
                                                              
 $test->addTestCase(new Doctrine_Query_Limit_TestCase());
@@ -149,6 +151,8 @@ $test->addTestCase(new Doctrine_Query_Delete_TestCase());
 $test->addTestCase(new Doctrine_Query_Update_TestCase());
 
 
+$test->addTestCase(new Doctrine_EnumTestCase());
+
 //$test->addTestCase(new Doctrine_Cache_FileTestCase());
 //$test->addTestCase(new Doctrine_Cache_SqliteTestCase());