diff --git a/Doctrine/Query.php b/Doctrine/Query.php index d867a4150..ae858dfa6 100644 --- a/Doctrine/Query.php +++ b/Doctrine/Query.php @@ -39,6 +39,10 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { * @param boolean $limitSubqueryUsed */ private $limitSubqueryUsed = false; + + private $tableStack; + + private $relationStack = array(); /** * create * returns a new Doctrine_Query object @@ -48,6 +52,14 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { public static function create() { return new Doctrine_Query(); } + + public function getTableStack() { + return $this->tableStack; + } + + public function getRelationStack() { + return $this->relationStack; + } /** * count * @@ -626,7 +638,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $e = preg_split("/[.:]/",$path); $index = 0; $currPath = ''; - + $this->tableStack = array(); foreach($e as $key => $fullname) { try { $copy = $e; @@ -723,7 +735,10 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $this->tableAliases[$currPath] = $tname2; $tableName = $tname2; + + $this->relationStack[] = $fk; } + $this->tableStack[] = $table; if( ! isset($this->tables[$tableName])) { $this->tables[$tableName] = $table; diff --git a/Doctrine/Query/Where.php b/Doctrine/Query/Where.php index 5624bb346..76f69fd69 100644 --- a/Doctrine/Query/Where.php +++ b/Doctrine/Query/Where.php @@ -29,23 +29,60 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition { $count = count($a); - $table = $this->query->load($reference, false); - switch($operator) { - case '=': - $alias = $this->query->getTableAlias($reference); - $table = $this->query->getTable($alias); - $enumIndex = $table->enumIndex($field, trim($value,"'")); - if($enumIndex !== false) - $value = $enumIndex; + $pos = strpos($field, "("); - $where = $alias.'.'.$field.' '.$operator.' '.$value; - break; - default: + if($pos !== false) { + $func = substr($field, 0, $pos); + $value = substr($field, ($pos + 1), -1); + $field = array_pop($a); + $reference = implode(".",$a); + $table = $this->query->load($reference, false); + array_pop($a); + $reference2 = implode('.', $a); + $alias = $this->query->getTableAlias($reference2); - $where = $this->query->getTableAlias($reference).'.'.$field.' '.$operator.' '.$value; + $stack = $this->query->getRelationStack(); + $relation = end($stack); + + $stack = $this->query->getTableStack(); + + switch($func) { + case 'contains': + + case 'similarTo': + case 'isLike': + if(empty($relation)) + throw new Doctrine_Query_Exception('DQL function contains can only be used for fields of related components'); + + $where = $alias.'.'.$relation->getLocal(). + ' IN (SELECT '.$relation->getForeign(). + ' FROM '.$relation->getTable()->getTableName().' WHERE '.$field.' = '.$value.')'; + break; + default: + throw new Doctrine_Query_Exception('Unknown DQL function: '.$func); + } + } else { + $table = $this->query->load($reference, false); + $enumIndex = $table->enumIndex($field, trim($value,"'")); + $alias = $this->query->getTableAlias($reference); + $table = $this->query->getTable($alias); + + switch($operator) { + case '<': + case '>': + case '=': + if($enumIndex !== false) + $value = $enumIndex; + + $where = $alias.'.'.$field.' '.$operator.' '.$value; + break; + default: + $where = $this->query->getTableAlias($reference).'.'.$field.' '.$operator.' '.$value; + } } - } + } else + throw new Doctrine_Query_Exception('Unknown component path. The correct format should be component1.component2 ... componentN.field'); return $where; } diff --git a/tests/QueryTestCase.php b/tests/QueryTestCase.php index b69f781b5..e2c4ccff0 100644 --- a/tests/QueryTestCase.php +++ b/tests/QueryTestCase.php @@ -29,6 +29,38 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { parent::prepareTables(); $this->connection->clear(); } + public function testUnknownFunction() { + $q = new Doctrine_Query(); + $f = false; + try { + $q->from('User')->where('User.name.someunknownfunc()'); + } catch(Doctrine_Query_Exception $e) { + $f = true; + } + $this->assertTrue($f); + } + public function testDqlContainsFunction() { + $q = new Doctrine_Query(); + $this->connection->clear(); + + $q->from('User')->where('User.Phonenumber.phonenumber.contains(?)'); + $this->assertEqual(count($q->getTableStack()), 2); + $this->assertEqual(count($q->getRelationStack()), 1); + + //print Doctrine_Lib::formatSql($q->getQuery()); + + $coll = $q->execute(array('123 123')); + + $this->assertEqual($q->getQuery(), 'SELECT entity.id AS entity__id, entity.name AS entity__name, entity.loginname AS entity__loginname, entity.password AS entity__password, entity.type AS entity__type, entity.created AS entity__created, entity.updated AS entity__updated, entity.email_id AS entity__email_id FROM entity LEFT JOIN phonenumber ON entity.id = phonenumber.entity_id WHERE entity.id IN (SELECT entity_id FROM phonenumber WHERE phonenumber = ?) AND (entity.type = 0)'); + + $this->assertEqual($coll->count(), 3); + $this->assertEqual($coll[0]->name, 'zYne'); + $this->assertEqual($coll[0]->Phonenumber->count(), 1); + $this->assertEqual($coll[1]->Phonenumber->count(), 3); + $this->assertEqual($coll[2]->Phonenumber->count(), 1); + + + } public function testEnumConversion() { $e[0] = new EnumTest(); diff --git a/tests/run.php b/tests/run.php index 3dc185107..6f5383e3f 100644 --- a/tests/run.php +++ b/tests/run.php @@ -31,7 +31,7 @@ require_once("ImportTestCase.php"); error_reporting(E_ALL); $test = new GroupTest("Doctrine Framework Unit Tests"); - +/** $test->addTestCase(new Doctrine_AccessTestCase()); $test->addTestCase(new Doctrine_EventListenerTestCase()); @@ -73,7 +73,7 @@ $test->addTestCase(new Doctrine_ImportTestCase()); $test->addTestCase(new Doctrine_ValidatorTestCase()); $test->addTestCase(new Doctrine_CollectionTestCase()); - +*/ $test->addTestCase(new Doctrine_QueryTestCase());