Commit 10439800 authored by romanb's avatar romanb

[2.0] Parser work.

parent 84c62d8a
...@@ -33,7 +33,6 @@ use \ArrayIterator; ...@@ -33,7 +33,6 @@ use \ArrayIterator;
* *
* @author Roman S. Borschel <roman@code-factory.org> * @author Roman S. Borschel <roman@code-factory.org>
* @since 2.0 * @since 2.0
* @todo Consider extending ArrayObject
*/ */
class Collection implements Countable, IteratorAggregate, ArrayAccess class Collection implements Countable, IteratorAggregate, ArrayAccess
{ {
...@@ -310,6 +309,7 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess ...@@ -310,6 +309,7 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
/** /**
* Checks whether the collection is empty. * Checks whether the collection is empty.
*
* Note: This is preferrable over count() == 0. * Note: This is preferrable over count() == 0.
* *
* @return boolean TRUE if the collection is empty, FALSE otherwise. * @return boolean TRUE if the collection is empty, FALSE otherwise.
......
...@@ -603,15 +603,15 @@ class Connection ...@@ -603,15 +603,15 @@ class Connection
} }
if ( ! empty($params)) { if ( ! empty($params)) {
$stmt = $this->prepare($query); $stmt = $this->_conn->prepare($query);
$stmt->execute($params); $stmt->execute($params);
return $stmt;
} else { } else {
$stmt = $this->_conn->query($query); $stmt = $this->_conn->query($query);
}
$this->_queryCount++; $this->_queryCount++;
return $stmt; return $stmt;
} }
}
/** /**
* Executes an SQL INSERT/UPDATE/DELETE query with the given parameters. * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters.
...@@ -630,14 +630,15 @@ class Connection ...@@ -630,14 +630,15 @@ class Connection
} }
if ( ! empty($params)) { if ( ! empty($params)) {
$stmt = $this->prepare($query); $stmt = $this->_conn->prepare($query);
$stmt->execute($params); $stmt->execute($params);
return $stmt->rowCount(); $result = $stmt->rowCount();
} else { } else {
$count = $this->_conn->exec($query); $result = $this->_conn->exec($query);
$this->_queryCount++;
return $count;
} }
$this->_queryCount++;
return $result;
} }
/** /**
...@@ -769,23 +770,6 @@ class Connection ...@@ -769,23 +770,6 @@ class Connection
return true; return true;
} }
/**
* Quotes pattern (% and _) characters in a string)
*
* EXPERIMENTAL
*
* WARNING: this function is experimental and may change signature at
* any time until labelled as non-experimental
*
* @param string the input string to quote
*
* @return string quoted string
*/
protected function _escapePattern($text)
{
return $text;
}
/** /**
* Gets the wrapped driver connection. * Gets the wrapped driver connection.
* *
......
...@@ -1219,11 +1219,9 @@ abstract class AbstractPlatform ...@@ -1219,11 +1219,9 @@ abstract class AbstractPlatform
$item[$k] = (int) $value; $item[$k] = (int) $value;
} }
} }
} else { } else if (is_bool($item)) {
if (is_bool($item)) {
$item = (int) $item; $item = (int) $item;
} }
}
return $item; return $item;
} }
......
...@@ -14,7 +14,7 @@ class BooleanType extends Type ...@@ -14,7 +14,7 @@ class BooleanType extends Type
* *
* @override * @override
*/ */
public function convertToDatabaseValue($value, Doctrine_DatabasePlatform $platform) public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
{ {
return $platform->convertBooleans($value); return $platform->convertBooleans($value);
} }
...@@ -24,7 +24,7 @@ class BooleanType extends Type ...@@ -24,7 +24,7 @@ class BooleanType extends Type
* *
* @override * @override
*/ */
public function convertToObjectValue($value) public function convertToPHPValue($value)
{ {
return (bool) $value; return (bool) $value;
} }
......
...@@ -178,19 +178,23 @@ abstract class AbstractQuery ...@@ -178,19 +178,23 @@ abstract class AbstractQuery
* *
* @return array Defined parameters * @return array Defined parameters
*/ */
public function getParams($params = array()) public function getParameters($params = array())
{ {
if ($params) {
return array_merge($this->_params, $params); return array_merge($this->_params, $params);
} }
return $this->_params;
}
/** /**
* setParams * Gets a query parameter.
* *
* @param array $params * @param mixed $key The key (index or name) of the bound parameter.
* @return mixed The value of the bound parameter.
*/ */
public function setParams(array $params = array()) public function getParameter($key)
{ {
$this->_params = $params; return isset($this->_params[$key]) ? $this->_params[$key] : null;
} }
/** /**
...@@ -470,7 +474,7 @@ abstract class AbstractQuery ...@@ -470,7 +474,7 @@ abstract class AbstractQuery
$this->_hydrationMode = $hydrationMode; $this->_hydrationMode = $hydrationMode;
} }
$params = $this->getParams($params); $params = $this->getParameters($params);
// Check result cache // Check result cache
if ($cacheDriver = $this->getResultCacheDriver()) { if ($cacheDriver = $this->getResultCacheDriver()) {
...@@ -503,12 +507,15 @@ abstract class AbstractQuery ...@@ -503,12 +507,15 @@ abstract class AbstractQuery
} }
/** /**
* @nodoc * Prepares the given parameters for execution in an SQL statement.
*
* Note to inheritors: This method must return a numerically, continously indexed array,
* starting with index 0 where the values (the parameter values) are in the order
* in which the parameters appear in the SQL query.
*
* @return array The SQL parameter array.
*/ */
protected function _prepareParams(array $params) abstract protected function _prepareParams(array $params);
{
return $this->_em->getConnection()->getDatabasePlatform()->convertBooleans($params);
}
/** /**
* Executes the query and returns a reference to the resulting Statement object. * Executes the query and returns a reference to the resulting Statement object.
......
...@@ -71,6 +71,7 @@ class DynamicProxyGenerator ...@@ -71,6 +71,7 @@ class DynamicProxyGenerator
require $fileName; require $fileName;
} }
$proxyClassName = '\\' . self::$_ns . $proxyClassName; $proxyClassName = '\\' . self::$_ns . $proxyClassName;
return new $proxyClassName($this->_em, $class, $identifier); return new $proxyClassName($this->_em, $class, $identifier);
} }
...@@ -89,6 +90,7 @@ class DynamicProxyGenerator ...@@ -89,6 +90,7 @@ class DynamicProxyGenerator
require $fileName; require $fileName;
} }
$proxyClassName = '\\' . self::$_ns . $proxyClassName; $proxyClassName = '\\' . self::$_ns . $proxyClassName;
return new $proxyClassName($this->_em, $assoc, $owner); return new $proxyClassName($this->_em, $assoc, $owner);
} }
......
...@@ -859,6 +859,9 @@ final class ClassMetadata ...@@ -859,6 +859,9 @@ final class ClassMetadata
/** /**
* Extracts the identifier values of an entity of this class. * Extracts the identifier values of an entity of this class.
* *
* For composite identifiers, the identifier values are returned as an array
* with the same order as the field order in {@link identifier}.
*
* @param object $entity * @param object $entity
* @return mixed * @return mixed
*/ */
......
...@@ -63,6 +63,9 @@ class ManyToManyMapping extends AssociationMapping ...@@ -63,6 +63,9 @@ class ManyToManyMapping extends AssociationMapping
*/ */
public $joinTableColumns = array(); public $joinTableColumns = array();
/** FUTURE: The key column mapping, if any. The key column holds the keys of the Collection. */
//public $keyColumn;
/** /**
* Initializes a new ManyToManyMapping. * Initializes a new ManyToManyMapping.
* *
......
...@@ -42,24 +42,10 @@ namespace Doctrine\ORM\Mapping; ...@@ -42,24 +42,10 @@ namespace Doctrine\ORM\Mapping;
*/ */
class OneToManyMapping extends AssociationMapping class OneToManyMapping extends AssociationMapping
{ {
/** The target foreign key columns that reference the sourceKeyColumns. */
/* NOTE: Currently not used because uni-directional one-many not supported atm. */
//protected $_targetForeignKeyColumns;
/** The (typically primary) source key columns that are referenced by the targetForeignKeyColumns. */
/* NOTE: Currently not used because uni-directional one-many not supported atm. */
//protected $_sourceKeyColumns;
/** This maps the target foreign key columns to the corresponding (primary) source key columns. */
/* NOTE: Currently not used because uni-directional one-many not supported atm. */
//protected $_targetForeignKeysToSourceKeys;
/** This maps the (primary) source key columns to the corresponding target foreign key columns. */
/* NOTE: Currently not used because uni-directional one-many not supported atm. */
//protected $_sourceKeysToTargetForeignKeys;
/** Whether to delete orphaned elements (removed from the collection) */ /** Whether to delete orphaned elements (removed from the collection) */
public $deleteOrphans = false; public $deleteOrphans = false;
/** FUTURE: The key column mapping, if any. The key column holds the keys of the Collection. */
//public $keyColumn;
/** /**
* Initializes a new OneToManyMapping. * Initializes a new OneToManyMapping.
......
...@@ -74,4 +74,21 @@ final class NativeQuery extends AbstractQuery ...@@ -74,4 +74,21 @@ final class NativeQuery extends AbstractQuery
{ {
return $this->_em->getConnection()->execute($this->_sql, $this->_prepareParams($params)); return $this->_em->getConnection()->execute($this->_sql, $this->_prepareParams($params));
} }
/**
* {@inheritdoc}
*
* @override
*/
protected function _prepareParams(array $params)
{
$sqlParams = array();
foreach ($params as $key => $value) {
$sqlParams[$key] = $value;
}
ksort($sqlParams);
return array_values($sqlParams);
}
} }
\ No newline at end of file
...@@ -26,6 +26,7 @@ use Doctrine\ORM\Mapping\AssociationMapping; ...@@ -26,6 +26,7 @@ use Doctrine\ORM\Mapping\AssociationMapping;
/** /**
* A PersistentCollection represents a collection of elements that have persistent state. * A PersistentCollection represents a collection of elements that have persistent state.
*
* Collections of entities represent only the associations (links) to those entities. * Collections of entities represent only the associations (links) to those entities.
* That means, if the collection is part of a many-many mapping and you remove * That means, if the collection is part of a many-many mapping and you remove
* entities from the collection, only the links in the relation table are removed (on flush). * entities from the collection, only the links in the relation table are removed (on flush).
......
...@@ -65,6 +65,16 @@ final class Query extends AbstractQuery ...@@ -65,6 +65,16 @@ final class Query extends AbstractQuery
*/ */
private $_parserResult; private $_parserResult;
/**
* @var integer The first result to return (the "offset").
*/
private $_firstResult = null;
/**
* @var integer The maximum number of results to return (the "limit").
*/
private $_maxResults = null;
/** /**
* @var CacheDriver The cache driver used for caching queries. * @var CacheDriver The cache driver used for caching queries.
*/ */
...@@ -100,7 +110,7 @@ final class Query extends AbstractQuery ...@@ -100,7 +110,7 @@ final class Query extends AbstractQuery
*/ */
public function getSql() public function getSql()
{ {
return $this->parse()->getSqlExecutor()->getSqlStatements(); return $this->_parse()->getSqlExecutor()->getSqlStatements();
} }
/** /**
...@@ -110,7 +120,7 @@ final class Query extends AbstractQuery ...@@ -110,7 +120,7 @@ final class Query extends AbstractQuery
* *
* @return Doctrine\ORM\Query\ParserResult * @return Doctrine\ORM\Query\ParserResult
*/ */
public function parse() private function _parse()
{ {
if ($this->_state === self::STATE_DIRTY) { if ($this->_state === self::STATE_DIRTY) {
$parser = new Parser($this); $parser = new Parser($this);
...@@ -121,15 +131,15 @@ final class Query extends AbstractQuery ...@@ -121,15 +131,15 @@ final class Query extends AbstractQuery
} }
/** /**
* _execute * {@inheritdoc}
* *
* @param array $params * @param array $params
* @return PDOStatement The executed PDOStatement. * @return Statement The resulting Statement.
* @override * @override
*/ */
protected function _doExecute(array $params) protected function _doExecute(array $params)
{ {
// If there is a CacheDriver associated to cache queries... // Check query cache
if ($queryCache = $this->getQueryCacheDriver()) { if ($queryCache = $this->getQueryCacheDriver()) {
// Calculate hash for dql query. // Calculate hash for dql query.
$hash = md5($this->getDql() . 'DOCTRINE_QUERY_CACHE_SALT'); $hash = md5($this->getDql() . 'DOCTRINE_QUERY_CACHE_SALT');
...@@ -137,7 +147,7 @@ final class Query extends AbstractQuery ...@@ -137,7 +147,7 @@ final class Query extends AbstractQuery
if ($cached === false) { if ($cached === false) {
// Cache miss. // Cache miss.
$executor = $this->parse()->getSqlExecutor(); $executor = $this->_parse()->getSqlExecutor();
$queryCache->save($hash, serialize($this->_parserResult), null); $queryCache->save($hash, serialize($this->_parserResult), null);
} else { } else {
// Cache hit. // Cache hit.
...@@ -145,20 +155,49 @@ final class Query extends AbstractQuery ...@@ -145,20 +155,49 @@ final class Query extends AbstractQuery
$executor = $this->_parserResult->getSqlExecutor(); $executor = $this->_parserResult->getSqlExecutor();
} }
} else { } else {
$executor = $this->parse()->getSqlExecutor(); $executor = $this->_parse()->getSqlExecutor();
} }
// Converting parameters
$params = $this->_prepareParams($params); $params = $this->_prepareParams($params);
if ( ! $this->_resultSetMapping) { if ( ! $this->_resultSetMapping) {
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping(); $this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
} }
// Executing the query and returning statement
return $executor->execute($this->_em->getConnection(), $params); return $executor->execute($this->_em->getConnection(), $params);
} }
/**
* {@inheritdoc}
*
* @override
*/
protected function _prepareParams(array $params)
{
$sqlParams = array();
$paramMappings = $this->_parserResult->getParameterMappings();
foreach ($params as $key => $value) {
if (is_object($value)) {
$values = $this->_em->getClassMetadata(get_class($value))->getIdentifierValues($value);
$sqlPositions = $paramMappings[$key];
$sqlParams = array_merge($sqlParams, array_combine((array)$sqlPositions, (array)$values));
} else if (is_bool($value)) {
$boolValue = $this->_em->getConnection()->getDatabasePlatform()->convertBooleans($value);
foreach ($paramMappings[$key] as $position) {
$sqlParams[$position] = $boolValue;
}
} else {
foreach ($paramMappings[$key] as $position) {
$sqlParams[$position] = $value;
}
}
}
ksort($sqlParams);
return array_values($sqlParams);
}
/** /**
* Defines a cache driver to be used for caching queries. * Defines a cache driver to be used for caching queries.
* *
...@@ -294,4 +333,50 @@ final class Query extends AbstractQuery ...@@ -294,4 +333,50 @@ final class Query extends AbstractQuery
{ {
return stripos($this->getDql(), $dql) === false ? false : true; return stripos($this->getDql(), $dql) === false ? false : true;
} }
/**
* Sets the position of the first result to retrieve (the "offset").
*
* @param integer $firstResult The first result to return.
* @return Query This query object.
*/
public function setFirstResult($firstResult)
{
$this->_firstResult = $firstResult;
return $this;
}
/**
* Gets the position of the first result the query object was set to retrieve (the "offset").
* Returns NULL if {@link setFirstResult} was not applied to this query.
*
* @return integer The position of the first result.
*/
public function getFirstResult()
{
return $this->_firstResult;
}
/**
* Sets the maximum number of results to retrieve (the "limit").
*
* @param integer $maxResults
* @return Query This query object.
*/
public function setMaxResults($maxResults)
{
$this->_maxResults = $maxResults;
return $this;
}
/**
* Gets the maximum number of results the query object was set to retrieve (the "limit").
* Returns NULL if {@link setMaxResults} was not applied to this query.
*
* @return integer Maximum number of results.
*/
public function getMaxResults()
{
return $this->_maxResults;
}
} }
\ No newline at end of file
<?php
namespace Doctrine\ORM\Query\AST;
/**
* CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
*
* @author Roman Borschel <roman@code-factory.org>
*/
class CollectionMemberExpression extends Node
{
public $entityExpression;
public $collectionValuedPathExpression;
public $isNot;
public function __construct($entityExpr, $collValuedPathExpr, $isNot)
{
$this->entityExpression = $entityExpr;
$this->collectionValuedPathExpression = $collValuedPathExpr;
$this->isNot = $isNot;
}
public function dispatch($walker)
{
return $walker->walkCollectionMemberExpression($this);
}
}
...@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions; ...@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions;
/** /**
* "ABS" "(" SimpleArithmeticExpression ")" * "ABS" "(" SimpleArithmeticExpression ")"
* *
* @author robo * @author Roman Borschel <roman@code-factory.org>
*/ */
class AbsFunction extends FunctionNode class AbsFunction extends FunctionNode
{ {
...@@ -37,7 +37,7 @@ class AbsFunction extends FunctionNode ...@@ -37,7 +37,7 @@ class AbsFunction extends FunctionNode
$lexer = $parser->getLexer(); $lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']); $parser->match($lexer->lookahead['value']);
$parser->match('('); $parser->match('(');
$this->_simpleArithmeticExpression = $parser->_SimpleArithmeticExpression(); $this->_simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(')'); $parser->match(')');
} }
} }
......
...@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions; ...@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions;
/** /**
* "CONCAT" "(" StringPrimary "," StringPrimary ")" * "CONCAT" "(" StringPrimary "," StringPrimary ")"
* *
* @author robo * @author Roman Borschel <roman@code-factory.org>
*/ */
class ConcatFunction extends FunctionNode class ConcatFunction extends FunctionNode
{ {
...@@ -36,13 +36,6 @@ class ConcatFunction extends FunctionNode ...@@ -36,13 +36,6 @@ class ConcatFunction extends FunctionNode
$sqlWalker->walkStringPrimary($this->_firstStringPrimary), $sqlWalker->walkStringPrimary($this->_firstStringPrimary),
$sqlWalker->walkStringPrimary($this->_secondStringPrimary) $sqlWalker->walkStringPrimary($this->_secondStringPrimary)
); );
/*
$sql = 'CONCAT(' .
$sqlWalker->walkStringPrimary($this->_firstStringPrimary)
. ', ' .
$sqlWalker->walkStringPrimary($this->_secondStringPrimary)
. ')';
return $sql;*/
} }
/** /**
...@@ -54,9 +47,9 @@ class ConcatFunction extends FunctionNode ...@@ -54,9 +47,9 @@ class ConcatFunction extends FunctionNode
$parser->match($lexer->lookahead['value']); $parser->match($lexer->lookahead['value']);
$parser->match('('); $parser->match('(');
$this->_firstStringPrimary = $parser->_StringPrimary(); $this->_firstStringPrimary = $parser->StringPrimary();
$parser->match(','); $parser->match(',');
$this->_secondStringPrimary = $parser->_StringPrimary(); $this->_secondStringPrimary = $parser->StringPrimary();
$parser->match(')'); $parser->match(')');
} }
......
...@@ -31,7 +31,6 @@ use Doctrine\ORM\Query\AST\Node; ...@@ -31,7 +31,6 @@ use Doctrine\ORM\Query\AST\Node;
abstract class FunctionNode extends Node abstract class FunctionNode extends Node
{ {
private $_name; private $_name;
//private $_expressions = array();
public function __construct($name) public function __construct($name)
{ {
......
...@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions; ...@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions;
/** /**
* "LENGTH" "(" StringPrimary ")" * "LENGTH" "(" StringPrimary ")"
* *
* @author robo * @author Roman Borschel <roman@code-factory.org>
*/ */
class LengthFunction extends FunctionNode class LengthFunction extends FunctionNode
{ {
...@@ -37,7 +37,7 @@ class LengthFunction extends FunctionNode ...@@ -37,7 +37,7 @@ class LengthFunction extends FunctionNode
$lexer = $parser->getLexer(); $lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']); $parser->match($lexer->lookahead['value']);
$parser->match('('); $parser->match('(');
$this->_stringPrimary = $parser->_StringPrimary(); $this->_stringPrimary = $parser->StringPrimary();
$parser->match(')'); $parser->match(')');
} }
} }
......
...@@ -57,12 +57,12 @@ class LocateFunction extends FunctionNode ...@@ -57,12 +57,12 @@ class LocateFunction extends FunctionNode
$lexer = $parser->getLexer(); $lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']); $parser->match($lexer->lookahead['value']);
$parser->match('('); $parser->match('(');
$this->_firstStringPrimary = $parser->_StringPrimary(); $this->_firstStringPrimary = $parser->StringPrimary();
$parser->match(','); $parser->match(',');
$this->_secondStringPrimary = $parser->_StringPrimary(); $this->_secondStringPrimary = $parser->StringPrimary();
if ($lexer->isNextToken(',')) { if ($lexer->isNextToken(',')) {
$parser->match(','); $parser->match(',');
$this->_simpleArithmeticExpression = $parser->_SimpleArithmeticExpression(); $this->_simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
} }
$parser->match(')'); $parser->match(')');
} }
......
...@@ -37,7 +37,7 @@ class LowerFunction extends FunctionNode ...@@ -37,7 +37,7 @@ class LowerFunction extends FunctionNode
$lexer = $parser->getLexer(); $lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']); $parser->match($lexer->lookahead['value']);
$parser->match('('); $parser->match('(');
$this->_stringPrimary = $parser->_StringPrimary(); $this->_stringPrimary = $parser->StringPrimary();
$parser->match(')'); $parser->match(')');
} }
} }
......
...@@ -47,9 +47,9 @@ class ModFunction extends FunctionNode ...@@ -47,9 +47,9 @@ class ModFunction extends FunctionNode
$lexer = $parser->getLexer(); $lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']); $parser->match($lexer->lookahead['value']);
$parser->match('('); $parser->match('(');
$this->_firstSimpleArithmeticExpression = $parser->_SimpleArithmeticExpression(); $this->_firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(','); $parser->match(',');
$this->_secondSimpleArithmeticExpression = $parser->_SimpleArithmeticExpression(); $this->_secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(')'); $parser->match(')');
} }
} }
......
...@@ -37,7 +37,7 @@ class SizeFunction extends FunctionNode ...@@ -37,7 +37,7 @@ class SizeFunction extends FunctionNode
$lexer = $parser->getLexer(); $lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']); $parser->match($lexer->lookahead['value']);
$parser->match('('); $parser->match('(');
$this->_collectionPathExpression = $parser->_CollectionValuedPathExpression(); $this->_collectionPathExpression = $parser->CollectionValuedPathExpression();
$parser->match(')'); $parser->match(')');
} }
} }
......
...@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions; ...@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions;
/** /**
* "SQRT" "(" SimpleArithmeticExpression ")" * "SQRT" "(" SimpleArithmeticExpression ")"
* *
* @author robo * @author Roman Borschel <roman@code-factory.org>
*/ */
class SqrtFunction extends FunctionNode class SqrtFunction extends FunctionNode
{ {
...@@ -37,7 +37,7 @@ class SqrtFunction extends FunctionNode ...@@ -37,7 +37,7 @@ class SqrtFunction extends FunctionNode
$lexer = $parser->getLexer(); $lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']); $parser->match($lexer->lookahead['value']);
$parser->match('('); $parser->match('(');
$this->_simpleArithmeticExpression = $parser->_SimpleArithmeticExpression(); $this->_simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(')'); $parser->match(')');
} }
} }
......
...@@ -57,11 +57,11 @@ class SubstringFunction extends FunctionNode ...@@ -57,11 +57,11 @@ class SubstringFunction extends FunctionNode
$parser->match($lexer->lookahead['value']); $parser->match($lexer->lookahead['value']);
$parser->match('('); $parser->match('(');
$this->_stringPrimary = $parser->_StringPrimary(); $this->_stringPrimary = $parser->StringPrimary();
$parser->match(','); $parser->match(',');
$this->_firstSimpleArithmeticExpression = $parser->_SimpleArithmeticExpression(); $this->_firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(','); $parser->match(',');
$this->_secondSimpleArithmeticExpression = $parser->_SimpleArithmeticExpression(); $this->_secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(')'); $parser->match(')');
} }
......
...@@ -75,7 +75,7 @@ class TrimFunction extends FunctionNode ...@@ -75,7 +75,7 @@ class TrimFunction extends FunctionNode
if ($this->_leading) $sql .= 'LEADING '; if ($this->_leading) $sql .= 'LEADING ';
else if ($this->_trailing) $sql .= 'TRAILING '; else if ($this->_trailing) $sql .= 'TRAILING ';
else if ($this->_both) $sql .= 'BOTH '; else if ($this->_both) $sql .= 'BOTH ';
if ($this->_trimChar) $sql .= $this->_trimChar . ' '; //TODO: quote() if ($this->_trimChar) $sql .= $sqlWalker->getConnection()->quote($this->_trimChar) . ' ';
$sql .= 'FROM ' . $sqlWalker->walkStringPrimary($this->_stringPrimary); $sql .= 'FROM ' . $sqlWalker->walkStringPrimary($this->_stringPrimary);
$sql .= ')'; $sql .= ')';
return $sql; return $sql;
...@@ -110,7 +110,7 @@ class TrimFunction extends FunctionNode ...@@ -110,7 +110,7 @@ class TrimFunction extends FunctionNode
$parser->match(Lexer::T_FROM); $parser->match(Lexer::T_FROM);
} }
$this->_stringPrimary = $parser->_StringPrimary(); $this->_stringPrimary = $parser->StringPrimary();
$parser->match(')'); $parser->match(')');
} }
......
...@@ -37,7 +37,7 @@ class UpperFunction extends FunctionNode ...@@ -37,7 +37,7 @@ class UpperFunction extends FunctionNode
$lexer = $parser->getLexer(); $lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']); $parser->match($lexer->lookahead['value']);
$parser->match('('); $parser->match('(');
$this->_stringPrimary = $parser->_StringPrimary(); $this->_stringPrimary = $parser->StringPrimary();
$parser->match(')'); $parser->match(')');
} }
} }
......
<?php
namespace Doctrine\ORM\Query\AST;
/**
* AST node for the following path expressions:
*
* AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
*
* SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
*
* StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression
*
* SingleValuedAssociationPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* SingleValuedAssociationField
*
* CollectionValuedPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* CollectionValuedAssociationField
*
* StateField ::= {EmbeddedClassStateField "."}* SimpleStateField
*
* SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField
*
* SimpleStateFieldAssociationPathExpression ::= SingleValuedAssociationPathExpression "." StateField
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
class PathExpression extends Node
{
const TYPE_COLLECTION_VALUED_ASSOCIATION = 1;
const TYPE_SINGLE_VALUED_ASSOCIATION = 2;
const TYPE_STATE_FIELD = 4;
private $_type;
private $_identificationVariable;
private $_parts;
public function __construct($type, $identificationVariable, array $parts)
{
$this->_type = $type;
$this->_identificationVariable = $identificationVariable;
$this->_parts = $parts;
}
public function getIdentificationVariable()
{
return $this->_identificationVariable;
}
public function getParts()
{
return $this->_parts;
}
public function getType()
{
return $this->_type;
}
public function dispatch($walker)
{
switch ($this->_type) {
case self::TYPE_STATE_FIELD:
return $walker->walkStateFieldPathExpression($this);
case self::TYPE_SINGLE_VALUED_ASSOCIATION:
return $walker->walkSingleValuedAssociationPathExpression($this);
case self::TYPE_COLLECTION_VALUED_ASSOCIATION:
return $walker->walkCollectionValuedAssociationPathExpression($this);
default:
throw new \Exception("Unexhaustive match.");
}
}
}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST;
/**
* SimpleStateFieldPathExpression ::= IdentificationVariable "." SimpleStateField
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.doctrine-project.org
* @since 2.0
* @version $Revision$
*/
class SimpleStateFieldPathExpression extends Node
{
private $_identificationVariable = null;
private $_simpleStateField = null;
public function __construct($identificationVariable, $simpleStateField)
{
$this->_identificationVariable = $identificationVariable;
$this->_simpleStateField = $simpleStateField;
}
/* Getters */
public function getIdentificationVariable()
{
return $this->_identificationVariable;
}
public function getSimpleStateField()
{
return $this->_simpleStateField;
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkSimpleStateFieldPathExpression($this);
}
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST;
/**
* StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression
*
* @author robo
*/
class StateFieldPathExpression extends Node
{
//const TYPE_COLLECTION_VALUED_ASSOCIATION = 1;
//const TYPE_SINGLE_VALUED_ASSOCIATION = 2;
//const TYPE_STATE_FIELD = 3;
//private $_type;
private $_parts;
// Information that is attached during semantical analysis.
private $_isSimpleStateFieldPathExpression = false;
private $_isSimpleStateFieldAssociationPathExpression = false;
private $_embeddedClassFields = array();
private $_singleValuedAssociationFields = array();
private $_collectionValuedAssociationFields = array();
public function __construct(array $parts)
{
$this->_parts = $parts;
}
public function getParts() {
return $this->_parts;
}
/**
* Gets whether the path expression represents a state field that is reached
* either directly (u.name) or by navigating over optionally many embedded class instances
* (u.address.zip).
*
* @return boolean
*/
public function isSimpleStateFieldPathExpression()
{
return $this->_isSimpleStateFieldPathExpression;
}
/**
* Gets whether the path expression represents a state field that is reached
* by navigating over at least one single-valued association and optionally
* many embedded class instances. (u.Group.address.zip, u.Group.address, ...)
*
* @return boolean
*/
public function isSimpleStateFieldAssociationPathExpression()
{
return $this->_isSimpleStateFieldAssociationPathExpression;
}
public function isPartEmbeddedClassField($part)
{
return isset($this->_embeddedClassFields[$part]);
}
public function isPartSingleValuedAssociationField($part)
{
return isset($this->_singleValuedAssociationFields[$part]);
}
public function isPartCollectionValuedAssociationField($part)
{
return isset($this->_collectionValuedAssociationFields[$part]);
}
/* Setters to attach semantical information during semantical analysis. */
public function setIsSimpleStateFieldPathExpression($bool)
{
$this->_isSimpleStateFieldPathExpression = $bool;
}
public function setIsSimpleStateFieldAssociationPathExpression($bool)
{
$this->_isSimpleStateFieldAssociationPathExpression = $bool;
}
public function setIsEmbeddedClassPart($part)
{
$this->_embeddedClassFields[$part] = true;
}
public function setIsSingleValuedAssociationPart($part)
{
$this->_singleValuedAssociationFields[$part] = true;
}
public function setIsCollectionValuedAssociationPart($part)
{
$this->_collectionValuedAssociationFields[$part] = true;
}
public function dispatch($sqlWalker)
{
return $sqlWalker->walkStateFieldPathExpression($this);
}
}
\ No newline at end of file
...@@ -88,6 +88,8 @@ class Lexer ...@@ -88,6 +88,8 @@ class Lexer
const T_WITH = 145; const T_WITH = 145;
const T_TRUE = 146; const T_TRUE = 146;
const T_FALSE = 147; const T_FALSE = 147;
const T_MEMBER = 148;
const T_OF = 149;
private $_keywordsTable; private $_keywordsTable;
...@@ -131,8 +133,8 @@ class Lexer ...@@ -131,8 +133,8 @@ class Lexer
/** /**
* Checks whether a given token matches the current lookahead. * Checks whether a given token matches the current lookahead.
* *
* @param <type> $token * @param integer|string $token
* @return <type> * @return boolean
*/ */
public function isNextToken($token) public function isNextToken($token)
{ {
...@@ -170,7 +172,7 @@ class Lexer ...@@ -170,7 +172,7 @@ class Lexer
* @param string $identifier identifier name * @param string $identifier identifier name
* @return int token type * @return int token type
*/ */
public function _checkLiteral($identifier) private function _checkLiteral($identifier)
{ {
$name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($identifier); $name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($identifier);
...@@ -237,6 +239,7 @@ class Lexer ...@@ -237,6 +239,7 @@ class Lexer
} }
if ($value[0] === "'" && $value[strlen($value) - 1] === "'") { if ($value[0] === "'" && $value[strlen($value) - 1] === "'") {
$type = self::T_STRING; $type = self::T_STRING;
$value = str_replace("''", "'", substr($value, 1, strlen($value) - 2));
} else if (ctype_alpha($value[0]) || $value[0] === '_') { } else if (ctype_alpha($value[0]) || $value[0] === '_') {
$type = $this->_checkLiteral($value); $type = $this->_checkLiteral($value);
} else if ($value[0] === '?' || $value[0] === ':') { } else if ($value[0] === '?' || $value[0] === ':') {
......
This diff is collapsed.
...@@ -35,8 +35,12 @@ namespace Doctrine\ORM\Query; ...@@ -35,8 +35,12 @@ namespace Doctrine\ORM\Query;
*/ */
class ParserResult class ParserResult
{ {
/** The SQL executor used for executing the SQL. */
private $_sqlExecutor; private $_sqlExecutor;
/** The ResultSetMapping that describes how to map the SQL result set. */
private $_resultSetMapping; private $_resultSetMapping;
/** The mappings of DQL parameter names/positions to SQL parameter positions. */
private $_parameterMappings;
/** /**
* Initializes a new instance of the <tt>ParserResult</tt> class. * Initializes a new instance of the <tt>ParserResult</tt> class.
...@@ -87,4 +91,37 @@ class ParserResult ...@@ -87,4 +91,37 @@ class ParserResult
{ {
return $this->_sqlExecutor; return $this->_sqlExecutor;
} }
/**
* Adds a DQL to SQL parameter mapping. One DQL parameter name/position can map to
* several SQL parameter positions.
*
* @param string|integer $dqlPosition
* @param integer $sqlPosition
*/
public function addParameterMapping($dqlPosition, $sqlPosition)
{
$this->_parameterMappings[$dqlPosition][] = $sqlPosition;
}
/**
* Gets all DQL to SQL parameter mappings.
*
* @return array The parameter mappings.
*/
public function getParameterMappings()
{
return $this->_parameterMappings;
}
/**
* Gets the SQL parameter positions for a DQL parameter name/position.
*
* @param string|integer $dqlPosition The name or position of the DQL parameter.
* @return array The positions of the corresponding SQL parameters.
*/
public function getSqlParameterPositions($dqlPosition)
{
return $this->_parameterMappings[$dqlPosition];
}
} }
\ No newline at end of file
This diff is collapsed.
<?php
namespace Doctrine\ORM\Query;
/**
* Interface for walkers of DQL ASTs (abstract syntax trees).
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
interface TreeWalker
{
/**
* Walks down a SelectStatement AST node, thereby generating the appropriate SQL.
*
* @return string The SQL.
*/
function walkSelectStatement(AST\SelectStatement $AST);
/**
* Walks down a SelectClause AST node, thereby generating the appropriate SQL.
*
* @return string The SQL.
*/
function walkSelectClause($selectClause);
/**
* Walks down a FromClause AST node, thereby generating the appropriate SQL.
*
* @return string The SQL.
*/
function walkFromClause($fromClause);
/**
* Walks down a FunctionNode AST node, thereby generating the appropriate SQL.
*
* @return string The SQL.
*/
function walkFunction($function);
/**
* Walks down an OrderByClause AST node, thereby generating the appropriate SQL.
*
* @param OrderByClause
* @return string The SQL.
*/
function walkOrderByClause($orderByClause);
/**
* Walks down an OrderByItem AST node, thereby generating the appropriate SQL.
*
* @param OrderByItem
* @return string The SQL.
*/
function walkOrderByItem($orderByItem);
/**
* Walks down a HavingClause AST node, thereby generating the appropriate SQL.
*
* @param HavingClause
* @return string The SQL.
*/
function walkHavingClause($havingClause);
/**
* Walks down a JoinVariableDeclaration AST node and creates the corresponding SQL.
*
* @param JoinVariableDeclaration $joinVarDecl
* @return string The SQL.
*/
function walkJoinVariableDeclaration($joinVarDecl);
/**
* Walks down a SelectExpression AST node and generates the corresponding SQL.
*
* @param SelectExpression $selectExpression
* @return string The SQL.
*/
function walkSelectExpression($selectExpression);
/**
* Walks down a QuantifiedExpression AST node, thereby generating the appropriate SQL.
*
* @param QuantifiedExpression
* @return string The SQL.
*/
function walkQuantifiedExpression($qExpr);
/**
* Walks down a Subselect AST node, thereby generating the appropriate SQL.
*
* @param Subselect
* @return string The SQL.
*/
function walkSubselect($subselect);
/**
* Walks down a SubselectFromClause AST node, thereby generating the appropriate SQL.
*
* @param SubselectFromClause
* @return string The SQL.
*/
function walkSubselectFromClause($subselectFromClause);
/**
* Walks down a SimpleSelectClause AST node, thereby generating the appropriate SQL.
*
* @param SimpleSelectClause
* @return string The SQL.
*/
function walkSimpleSelectClause($simpleSelectClause);
/**
* Walks down a SimpleSelectExpression AST node, thereby generating the appropriate SQL.
*
* @param SimpleSelectExpression
* @return string The SQL.
*/
function walkSimpleSelectExpression($simpleSelectExpression);
/**
* Walks down an AggregateExpression AST node, thereby generating the appropriate SQL.
*
* @param AggregateExpression
* @return string The SQL.
*/
function walkAggregateExpression($aggExpression);
/**
* Walks down a GroupByClause AST node, thereby generating the appropriate SQL.
*
* @param GroupByClause
* @return string The SQL.
*/
function walkGroupByClause($groupByClause);
/**
* Walks down a GroupByItem AST node, thereby generating the appropriate SQL.
*
* @param GroupByItem
* @return string The SQL.
*/
function walkGroupByItem(AST\PathExpression $pathExpr);
/**
* Walks down an UpdateStatement AST node, thereby generating the appropriate SQL.
*
* @param UpdateStatement
* @return string The SQL.
*/
function walkUpdateStatement(AST\UpdateStatement $AST);
/**
* Walks down a DeleteStatement AST node, thereby generating the appropriate SQL.
*
* @param DeleteStatement
* @return string The SQL.
*/
function walkDeleteStatement(AST\DeleteStatement $AST);
/**
* Walks down a DeleteClause AST node, thereby generating the appropriate SQL.
*
* @param DeleteClause
* @return string The SQL.
*/
function walkDeleteClause(AST\DeleteClause $deleteClause);
/**
* Walks down an UpdateClause AST node, thereby generating the appropriate SQL.
*
* @param UpdateClause
* @return string The SQL.
*/
function walkUpdateClause($updateClause);
/**
* Walks down an UpdateItem AST node, thereby generating the appropriate SQL.
*
* @param UpdateItem
* @return string The SQL.
*/
function walkUpdateItem($updateItem);
/**
* Walks down a WhereClause AST node, thereby generating the appropriate SQL.
*
* @param WhereClause
* @return string The SQL.
*/
function walkWhereClause($whereClause);
/**
* Walks down a ConditionalTerm AST node, thereby generating the appropriate SQL.
*
* @param ConditionalTerm
* @return string The SQL.
*/
function walkConditionalTerm($condTerm);
/**
* Walks down a ConditionalFactor AST node, thereby generating the appropriate SQL.
*
* @param ConditionalFactor
* @return string The SQL.
*/
function walkConditionalFactor($factor);
/**
* Walks down an ExistsExpression AST node, thereby generating the appropriate SQL.
*
* @param ExistsExpression
* @return string The SQL.
*/
function walkExistsExpression($existsExpr);
/**
* Walks down a CollectionMemberExpression AST node, thereby generating the appropriate SQL.
*
* @param CollectionMemberExpression
* @return string The SQL.
*/
function walkCollectionMemberExpression($collMemberExpr);
/**
* Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL.
*
* @param NullComparisonExpression
* @return string The SQL.
*/
function walkNullComparisonExpression($nullCompExpr);
/**
* Walks down an InExpression AST node, thereby generating the appropriate SQL.
*
* @param InExpression
* @return string The SQL.
*/
function walkInExpression($inExpr);
/**
* Walks down a literal that represents an AST node, thereby generating the appropriate SQL.
*
* @param mixed
* @return string The SQL.
*/
function walkLiteral($literal);
/**
* Walks down a BetweenExpression AST node, thereby generating the appropriate SQL.
*
* @param BetweenExpression
* @return string The SQL.
*/
function walkBetweenExpression($betweenExpr);
/**
* Walks down a LikeExpression AST node, thereby generating the appropriate SQL.
*
* @param LikeExpression
* @return string The SQL.
*/
function walkLikeExpression($likeExpr);
/**
* Walks down a StateFieldPathExpression AST node, thereby generating the appropriate SQL.
*
* @param StateFieldPathExpression
* @return string The SQL.
*/
function walkStateFieldPathExpression($stateFieldPathExpression);
/**
* Walks down a ComparisonExpression AST node, thereby generating the appropriate SQL.
*
* @param ComparisonExpression
* @return string The SQL.
*/
function walkComparisonExpression($compExpr);
/**
* Walks down an InputParameter AST node, thereby generating the appropriate SQL.
*
* @param InputParameter
* @return string The SQL.
*/
function walkInputParameter($inputParam);
/**
* Walks down an ArithmeticExpression AST node, thereby generating the appropriate SQL.
*
* @param ArithmeticExpression
* @return string The SQL.
*/
function walkArithmeticExpression($arithmeticExpr);
/**
* Walks down an ArithmeticTerm AST node, thereby generating the appropriate SQL.
*
* @param mixed
* @return string The SQL.
*/
function walkArithmeticTerm($term);
/**
* Walks down a StringPrimary that represents an AST node, thereby generating the appropriate SQL.
*
* @param mixed
* @return string The SQL.
*/
function walkStringPrimary($stringPrimary);
/**
* Walks down an ArithmeticFactor that represents an AST node, thereby generating the appropriate SQL.
*
* @param mixed
* @return string The SQL.
*/
function walkArithmeticFactor($factor);
/**
* Walks down an SimpleArithmeticExpression AST node, thereby generating the appropriate SQL.
*
* @param SimpleArithmeticExpression
* @return string The SQL.
*/
function walkSimpleArithmeticExpression($simpleArithmeticExpr);
/**
* Walks down an PathExpression AST node, thereby generating the appropriate SQL.
*
* @param mixed
* @return string The SQL.
*/
function walkPathExpression($pathExpr);
}
\ No newline at end of file
<?php
namespace Doctrine\ORM\Query;
/**
* An adapter implementation of the TreeWalker interface. The methods in this class
* are empty. This class exists as convenience for creating tree walkers.
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
abstract class TreeWalkerAdapter implements TreeWalker
{
/**
* Walks down a SelectStatement AST node, thereby generating the appropriate SQL.
*
* @return string The SQL.
*/
public function walkSelectStatement(AST\SelectStatement $AST) {}
/**
* Walks down a SelectClause AST node, thereby generating the appropriate SQL.
*
* @return string The SQL.
*/
public function walkSelectClause($selectClause) {}
/**
* Walks down a FromClause AST node, thereby generating the appropriate SQL.
*
* @return string The SQL.
*/
public function walkFromClause($fromClause) {}
/**
* Walks down a FunctionNode AST node, thereby generating the appropriate SQL.
*
* @return string The SQL.
*/
public function walkFunction($function) {}
/**
* Walks down an OrderByClause AST node, thereby generating the appropriate SQL.
*
* @param OrderByClause
* @return string The SQL.
*/
public function walkOrderByClause($orderByClause) {}
/**
* Walks down an OrderByItem AST node, thereby generating the appropriate SQL.
*
* @param OrderByItem
* @return string The SQL.
*/
public function walkOrderByItem($orderByItem) {}
/**
* Walks down a HavingClause AST node, thereby generating the appropriate SQL.
*
* @param HavingClause
* @return string The SQL.
*/
public function walkHavingClause($havingClause) {}
/**
* Walks down a JoinVariableDeclaration AST node and creates the corresponding SQL.
*
* @param JoinVariableDeclaration $joinVarDecl
* @return string The SQL.
*/
public function walkJoinVariableDeclaration($joinVarDecl) {}
/**
* Walks down a SelectExpression AST node and generates the corresponding SQL.
*
* @param SelectExpression $selectExpression
* @return string The SQL.
*/
public function walkSelectExpression($selectExpression) {}
/**
* Walks down a QuantifiedExpression AST node, thereby generating the appropriate SQL.
*
* @param QuantifiedExpression
* @return string The SQL.
*/
public function walkQuantifiedExpression($qExpr) {}
/**
* Walks down a Subselect AST node, thereby generating the appropriate SQL.
*
* @param Subselect
* @return string The SQL.
*/
public function walkSubselect($subselect) {}
/**
* Walks down a SubselectFromClause AST node, thereby generating the appropriate SQL.
*
* @param SubselectFromClause
* @return string The SQL.
*/
public function walkSubselectFromClause($subselectFromClause) {}
/**
* Walks down a SimpleSelectClause AST node, thereby generating the appropriate SQL.
*
* @param SimpleSelectClause
* @return string The SQL.
*/
public function walkSimpleSelectClause($simpleSelectClause) {}
/**
* Walks down a SimpleSelectExpression AST node, thereby generating the appropriate SQL.
*
* @param SimpleSelectExpression
* @return string The SQL.
*/
public function walkSimpleSelectExpression($simpleSelectExpression) {}
/**
* Walks down an AggregateExpression AST node, thereby generating the appropriate SQL.
*
* @param AggregateExpression
* @return string The SQL.
*/
public function walkAggregateExpression($aggExpression) {}
/**
* Walks down a GroupByClause AST node, thereby generating the appropriate SQL.
*
* @param GroupByClause
* @return string The SQL.
*/
public function walkGroupByClause($groupByClause) {}
/**
* Walks down a GroupByItem AST node, thereby generating the appropriate SQL.
*
* @param GroupByItem
* @return string The SQL.
*/
public function walkGroupByItem(AST\PathExpression $pathExpr) {}
/**
* Walks down an UpdateStatement AST node, thereby generating the appropriate SQL.
*
* @param UpdateStatement
* @return string The SQL.
*/
public function walkUpdateStatement(AST\UpdateStatement $AST) {}
/**
* Walks down a DeleteStatement AST node, thereby generating the appropriate SQL.
*
* @param DeleteStatement
* @return string The SQL.
*/
public function walkDeleteStatement(AST\DeleteStatement $AST) {}
/**
* Walks down a DeleteClause AST node, thereby generating the appropriate SQL.
*
* @param DeleteClause
* @return string The SQL.
*/
public function walkDeleteClause(AST\DeleteClause $deleteClause) {}
/**
* Walks down an UpdateClause AST node, thereby generating the appropriate SQL.
*
* @param UpdateClause
* @return string The SQL.
*/
public function walkUpdateClause($updateClause) {}
/**
* Walks down an UpdateItem AST node, thereby generating the appropriate SQL.
*
* @param UpdateItem
* @return string The SQL.
*/
public function walkUpdateItem($updateItem) {}
/**
* Walks down a WhereClause AST node, thereby generating the appropriate SQL.
*
* @param WhereClause
* @return string The SQL.
*/
public function walkWhereClause($whereClause) {}
/**
* Walks down a ConditionalTerm AST node, thereby generating the appropriate SQL.
*
* @param ConditionalTerm
* @return string The SQL.
*/
public function walkConditionalTerm($condTerm) {}
/**
* Walks down a ConditionalFactor AST node, thereby generating the appropriate SQL.
*
* @param ConditionalFactor
* @return string The SQL.
*/
public function walkConditionalFactor($factor) {}
/**
* Walks down an ExistsExpression AST node, thereby generating the appropriate SQL.
*
* @param ExistsExpression
* @return string The SQL.
*/
public function walkExistsExpression($existsExpr) {}
/**
* Walks down a CollectionMemberExpression AST node, thereby generating the appropriate SQL.
*
* @param CollectionMemberExpression
* @return string The SQL.
*/
public function walkCollectionMemberExpression($collMemberExpr) {}
/**
* Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL.
*
* @param NullComparisonExpression
* @return string The SQL.
*/
public function walkNullComparisonExpression($nullCompExpr) {}
/**
* Walks down an InExpression AST node, thereby generating the appropriate SQL.
*
* @param InExpression
* @return string The SQL.
*/
public function walkInExpression($inExpr) {}
/**
* Walks down a literal that represents an AST node, thereby generating the appropriate SQL.
*
* @param mixed
* @return string The SQL.
*/
public function walkLiteral($literal) {}
/**
* Walks down a BetweenExpression AST node, thereby generating the appropriate SQL.
*
* @param BetweenExpression
* @return string The SQL.
*/
public function walkBetweenExpression($betweenExpr) {}
/**
* Walks down a LikeExpression AST node, thereby generating the appropriate SQL.
*
* @param LikeExpression
* @return string The SQL.
*/
public function walkLikeExpression($likeExpr) {}
/**
* Walks down a StateFieldPathExpression AST node, thereby generating the appropriate SQL.
*
* @param StateFieldPathExpression
* @return string The SQL.
*/
public function walkStateFieldPathExpression($stateFieldPathExpression) {}
/**
* Walks down a ComparisonExpression AST node, thereby generating the appropriate SQL.
*
* @param ComparisonExpression
* @return string The SQL.
*/
public function walkComparisonExpression($compExpr) {}
/**
* Walks down an InputParameter AST node, thereby generating the appropriate SQL.
*
* @param InputParameter
* @return string The SQL.
*/
public function walkInputParameter($inputParam) {}
/**
* Walks down an ArithmeticExpression AST node, thereby generating the appropriate SQL.
*
* @param ArithmeticExpression
* @return string The SQL.
*/
public function walkArithmeticExpression($arithmeticExpr) {}
/**
* Walks down an ArithmeticTerm AST node, thereby generating the appropriate SQL.
*
* @param mixed
* @return string The SQL.
*/
public function walkArithmeticTerm($term) {}
/**
* Walks down a StringPrimary that represents an AST node, thereby generating the appropriate SQL.
*
* @param mixed
* @return string The SQL.
*/
public function walkStringPrimary($stringPrimary) {}
/**
* Walks down an ArithmeticFactor that represents an AST node, thereby generating the appropriate SQL.
*
* @param mixed
* @return string The SQL.
*/
public function walkArithmeticFactor($factor) {}
/**
* Walks down an SimpleArithmeticExpression AST node, thereby generating the appropriate SQL.
*
* @param SimpleArithmeticExpression
* @return string The SQL.
*/
public function walkSimpleArithmeticExpression($simpleArithmeticExpr) {}
/**
* Walks down an PathExpression AST node, thereby generating the appropriate SQL.
*
* @param mixed
* @return string The SQL.
*/
public function walkPathExpression($pathExpr) {}
}
\ No newline at end of file
...@@ -224,6 +224,7 @@ class SchemaTool ...@@ -224,6 +224,7 @@ class SchemaTool
if (isset($class->inheritedAssociationFields[$fieldName])) { if (isset($class->inheritedAssociationFields[$fieldName])) {
continue; continue;
} }
$foreignClass = $this->_em->getClassMetadata($mapping->targetEntityName); $foreignClass = $this->_em->getClassMetadata($mapping->targetEntityName);
if ($mapping->isOneToOne() && $mapping->isOwningSide) { if ($mapping->isOneToOne() && $mapping->isOwningSide) {
$constraint = array(); $constraint = array();
......
...@@ -403,9 +403,11 @@ class UnitOfWork implements PropertyChangedListener ...@@ -403,9 +403,11 @@ class UnitOfWork implements PropertyChangedListener
&& $actualData[$name] !== null && $actualData[$name] !== null
&& ! ($actualData[$name] instanceof PersistentCollection) && ! ($actualData[$name] instanceof PersistentCollection)
) { ) {
//TODO: If $actualData[$name] is Collection then unwrap the array // If $actualData[$name] is Collection then unwrap the array
if ($actualData[$name] instanceof Collection) {
$actualData[$name] = $actualData[$name]->unwrap();
}
$assoc = $class->associationMappings[$name]; $assoc = $class->associationMappings[$name];
//echo PHP_EOL . "INJECTING PCOLL into $name" . PHP_EOL;
// Inject PersistentCollection // Inject PersistentCollection
$coll = new PersistentCollection($this->_em, $this->_em->getClassMetadata($assoc->targetEntityName), $coll = new PersistentCollection($this->_em, $this->_em->getClassMetadata($assoc->targetEntityName),
$actualData[$name] ? $actualData[$name] : array()); $actualData[$name] ? $actualData[$name] : array());
......
...@@ -19,9 +19,9 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase ...@@ -19,9 +19,9 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase
{ {
$this->_coll->add("one"); $this->_coll->add("one");
$this->_coll->add("two"); $this->_coll->add("two");
$exists = $this->_coll->exists(function($key, $element) { return $element == "one"; }); $exists = $this->_coll->exists(function($k, $e) { return $e == "one"; });
$this->assertTrue($exists); $this->assertTrue($exists);
$exists = $this->_coll->exists(function($key, $element) { return $element == "other"; }); $exists = $this->_coll->exists(function($k, $e) { return $e == "other"; });
$this->assertFalse($exists); $this->assertFalse($exists);
} }
...@@ -29,7 +29,7 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase ...@@ -29,7 +29,7 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase
{ {
$this->_coll->add(1); $this->_coll->add(1);
$this->_coll->add(2); $this->_coll->add(2);
$res = $this->_coll->map(function ($e) { return $e * 2; }); $res = $this->_coll->map(function($e) { return $e * 2; });
$this->assertEquals(array(2, 4), $res->unwrap()); $this->assertEquals(array(2, 4), $res->unwrap());
} }
...@@ -38,7 +38,7 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase ...@@ -38,7 +38,7 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase
$this->_coll->add(1); $this->_coll->add(1);
$this->_coll->add("foo"); $this->_coll->add("foo");
$this->_coll->add(3); $this->_coll->add(3);
$res = $this->_coll->filter(function ($e) { return is_numeric($e); }); $res = $this->_coll->filter(function($e) { return is_numeric($e); });
$this->assertEquals(array(0 => 1, 2 => 3), $res->unwrap()); $this->assertEquals(array(0 => 1, 2 => 3), $res->unwrap());
} }
...@@ -66,39 +66,39 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase ...@@ -66,39 +66,39 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase
public function testContainsKey() public function testContainsKey()
{ {
$this->_coll[5] = 'five'; $this->_coll[5] = 'five';
$this->assertEquals($this->_coll->containsKey(5), true); $this->assertTrue($this->_coll->containsKey(5));
} }
public function testContains() public function testContains()
{ {
$this->_coll[0] = 'test'; $this->_coll[0] = 'test';
$this->assertEquals($this->_coll->contains('test'), true); $this->assertTrue($this->_coll->contains('test'));
} }
public function testSearch() public function testSearch()
{ {
$this->_coll[0] = 'test'; $this->_coll[0] = 'test';
$this->assertEquals($this->_coll->search('test'), 0); $this->assertEquals(0, $this->_coll->search('test'));
} }
public function testGet() public function testGet()
{ {
$this->_coll[0] = 'test'; $this->_coll[0] = 'test';
$this->assertEquals($this->_coll->get(0), 'test'); $this->assertEquals('test', $this->_coll->get(0));
} }
public function testGetKeys() public function testGetKeys()
{ {
$this->_coll[] = 'one'; $this->_coll[] = 'one';
$this->_coll[] = 'two'; $this->_coll[] = 'two';
$this->assertEquals($this->_coll->getKeys(), array(0, 1)); $this->assertEquals(array(0, 1), $this->_coll->getKeys());
} }
public function testGetElements() public function testGetElements()
{ {
$this->_coll[] = 'one'; $this->_coll[] = 'one';
$this->_coll[] = 'two'; $this->_coll[] = 'two';
$this->assertEquals($this->_coll->getElements(), array('one', 'two')); $this->assertEquals(array('one', 'two'), $this->_coll->getElements());
} }
public function testCount() public function testCount()
...@@ -113,15 +113,15 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase ...@@ -113,15 +113,15 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase
{ {
$this->_coll[] = 'one'; $this->_coll[] = 'one';
$this->_coll[] = 'two'; $this->_coll[] = 'two';
$this->assertEquals($this->_coll->forAll(function($key, $element) { return is_string($element); }), true); $this->assertEquals($this->_coll->forAll(function($k, $e) { return is_string($e); }), true);
$this->assertEquals($this->_coll->forAll(function($key, $element) { return is_array($element); }), false); $this->assertEquals($this->_coll->forAll(function($k, $e) { return is_array($e); }), false);
} }
public function testPartition() public function testPartition()
{ {
$this->_coll[] = true; $this->_coll[] = true;
$this->_coll[] = false; $this->_coll[] = false;
$partition = $this->_coll->partition(function($key, $element) { return $element == true; }); $partition = $this->_coll->partition(function($k, $e) { return $e == true; });
$this->assertEquals($partition[0][0], true); $this->assertEquals($partition[0][0], true);
$this->assertEquals($partition[1][0], false); $this->assertEquals($partition[1][0], false);
} }
......
...@@ -53,7 +53,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection ...@@ -53,7 +53,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
*/ */
public function quote($input, $type = null) public function quote($input, $type = null)
{ {
if ($type === 'string') { if (is_string($input)) {
return "'" . $input . "'"; return "'" . $input . "'";
} }
return $input; return $input;
......
<?php
namespace Doctrine\Tests\Mocks;
class MockTreeWalker extends \Doctrine\ORM\Query\TreeWalkerAdapter
{
}
...@@ -32,6 +32,14 @@ class CompanyPerson ...@@ -32,6 +32,14 @@ class CompanyPerson
*/ */
private $spouse; private $spouse;
/**
* @ManyToMany(targetEntity="CompanyPerson")
* @JoinTable(name="company_persons_friends",
joinColumns={{"name"="person_id", "referencedColumnName"="id"}},
inverseJoinColumns={{"name"="friend_id", "referencedColumnName"="id"}})
*/
private $friends;
public function getId() { public function getId() {
return $this->id; return $this->id;
} }
...@@ -48,6 +56,20 @@ class CompanyPerson ...@@ -48,6 +56,20 @@ class CompanyPerson
return $this->spouse; return $this->spouse;
} }
public function getFriends() {
return $this->friends;
}
public function addFriend(CompanyPerson $friend) {
if ( ! $this->friends) {
$this->friends = new \Doctrine\Common\Collections\Collection;
}
if ( ! $this->friends->contains($friend)) {
$this->friends->add($friend);
$friend->addFriend($this);
}
}
public function setSpouse(CompanyPerson $spouse) { public function setSpouse(CompanyPerson $spouse) {
if ($spouse !== $this->spouse) { if ($spouse !== $this->spouse) {
$this->spouse = $spouse; $this->spouse = $spouse;
......
...@@ -65,28 +65,6 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -65,28 +65,6 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(100000, $entities[0]->getSalary()); $this->assertEquals(100000, $entities[0]->getSalary());
$this->_em->clear(); $this->_em->clear();
/*
$query = $this->_em->createQuery("select r,o from Doctrine\Tests\ORM\Functional\RelatedEntity r join r.owner o");
$entities = $query->getResultList();
$this->assertEquals(1, count($entities));
$this->assertTrue($entities[0] instanceof RelatedEntity);
$this->assertTrue(is_numeric($entities[0]->getId()));
$this->assertEquals('theRelatedOne', $entities[0]->getName());
$this->assertTrue($entities[0]->getOwner() instanceof ChildEntity);
$this->assertEquals('thedata', $entities[0]->getOwner()->getData());
$this->assertSame($entities[0], $entities[0]->getOwner()->getRelatedEntity());
$query = $this->_em->createQuery("update Doctrine\Tests\ORM\Functional\ChildEntity e set e.data = 'newdata'");
$affected = $query->execute();
$this->assertEquals(1, $affected);
$query = $this->_em->createQuery("delete Doctrine\Tests\ORM\Functional\ParentEntity e");
$affected = $query->execute();
$this->assertEquals(2, $affected);
*/
} }
public function testMultiLevelUpdateAndFind() { public function testMultiLevelUpdateAndFind() {
...@@ -149,4 +127,37 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -149,4 +127,37 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals('John Smith', $result[0]->getSpouse()->getName()); $this->assertEquals('John Smith', $result[0]->getSpouse()->getName());
$this->assertSame($result[0], $result[0]->getSpouse()->getSpouse()); $this->assertSame($result[0], $result[0]->getSpouse()->getSpouse());
} }
public function testSelfReferencingManyToMany()
{
$person1 = new CompanyPerson;
$person1->setName('Roman');
$person2 = new CompanyPerson;
$person2->setName('Jonathan');
$person1->addFriend($person2);
$this->assertEquals(1, count($person1->getFriends()));
$this->assertEquals(1, count($person2->getFriends()));
$this->_em->save($person1);
$this->_em->save($person2);
$this->_em->flush();
$this->_em->clear();
$query = $this->_em->createQuery('select p, f from Doctrine\Tests\Models\Company\CompanyPerson p join p.friends f where p.name=?1');
$query->setParameter(1, 'Roman');
$result = $query->getResultList();
$this->assertEquals(1, count($result));
$this->assertEquals(1, count($result[0]->getFriends()));
$this->assertEquals('Roman', $result[0]->getName());
$friends = $result[0]->getFriends();
$this->assertEquals('Jonathan', $friends[0]->getName());
}
} }
...@@ -16,7 +16,9 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase ...@@ -16,7 +16,9 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
{ {
try { try {
$query = $this->_em->createQuery($dql); $query = $this->_em->createQuery($dql);
$parserResult = $query->parse(); $parser = new \Doctrine\ORM\Query\Parser($query);
$parser->setSqlTreeWalker(new \Doctrine\Tests\Mocks\MockTreeWalker);
$parserResult = $parser->parse();
} catch (\Exception $e) { } catch (\Exception $e) {
if ($debug) { if ($debug) {
echo $e->getTraceAsString() . PHP_EOL; echo $e->getTraceAsString() . PHP_EOL;
...@@ -30,15 +32,15 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase ...@@ -30,15 +32,15 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
try { try {
$query = $this->_em->createQuery($dql); $query = $this->_em->createQuery($dql);
$query->setDql($dql); $query->setDql($dql);
$parserResult = $query->parse(); $parser = new \Doctrine\ORM\Query\Parser($query);
$parser->setSqlTreeWalker(new \Doctrine\Tests\Mocks\MockTreeWalker);
$parserResult = $parser->parse();
$this->fail('No syntax errors were detected, when syntax errors were expected'); $this->fail('No syntax errors were detected, when syntax errors were expected');
} catch (\Exception $e) { } catch (\Exception $e) {
//echo $e->getMessage() . PHP_EOL;
if ($debug) { if ($debug) {
echo $e->getMessage() . PHP_EOL; echo $e->getMessage() . PHP_EOL;
echo $e->getTraceAsString() . PHP_EOL; echo $e->getTraceAsString() . PHP_EOL;
} }
// It was expected!
} }
} }
...@@ -319,4 +321,9 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase ...@@ -319,4 +321,9 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
{ {
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id > SOME (SELECT u2.id FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE u2.name = u.name)'); $this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id > SOME (SELECT u2.id FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE u2.name = u.name)');
} }
public function testMemberOfExpression()
{
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers');
}
} }
\ No newline at end of file
...@@ -182,7 +182,7 @@ class LexerTest extends \Doctrine\Tests\OrmTestCase ...@@ -182,7 +182,7 @@ class LexerTest extends \Doctrine\Tests\OrmTestCase
$lexer->moveNext(); $lexer->moveNext();
$token = $lexer->lookahead; $token = $lexer->lookahead;
$this->assertEquals(Lexer::T_STRING, $token['type']); $this->assertEquals(Lexer::T_STRING, $token['type']);
$this->assertEquals("'This is a string.'", $token['value']); $this->assertEquals("This is a string.", $token['value']);
} }
public function testScannerRecognizesStringContainingSingleQuotes() public function testScannerRecognizesStringContainingSingleQuotes()
...@@ -191,7 +191,7 @@ class LexerTest extends \Doctrine\Tests\OrmTestCase ...@@ -191,7 +191,7 @@ class LexerTest extends \Doctrine\Tests\OrmTestCase
$lexer->moveNext(); $lexer->moveNext();
$token = $lexer->lookahead; $token = $lexer->lookahead;
$this->assertEquals(Lexer::T_STRING, $token['type']); $this->assertEquals(Lexer::T_STRING, $token['type']);
$this->assertEquals("'abc''defg'''", $token['value']); $this->assertEquals("abc'defg'", $token['value']);
} }
public function testScannerRecognizesInputParameter() public function testScannerRecognizesInputParameter()
...@@ -269,7 +269,7 @@ class LexerTest extends \Doctrine\Tests\OrmTestCase ...@@ -269,7 +269,7 @@ class LexerTest extends \Doctrine\Tests\OrmTestCase
'position' => 47 'position' => 47
), ),
array( array(
'value' => "'Jack O''Neil'", 'value' => "Jack O'Neil",
'type' => Lexer::T_STRING, 'type' => Lexer::T_STRING,
'position' => 49 'position' => 49
) )
......
...@@ -21,7 +21,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ...@@ -21,7 +21,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$query->free(); $query->free();
} catch (Doctrine_Exception $e) { } catch (Doctrine_Exception $e) {
echo $e->getMessage(); echo $e->getMessage();
echo $e->getTraceAsString(); die(); echo $e->getTraceAsString();
$this->fail($e->getMessage()); $this->fail($e->getMessage());
} }
} }
...@@ -91,7 +91,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ...@@ -91,7 +91,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.username = :name', 'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.username = :name',
'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.username = :name' 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.username = ?'
); );
} }
...@@ -99,7 +99,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ...@@ -99,7 +99,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.username = :name and u.username = :name2', 'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.username = :name and u.username = :name2',
'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.username = :name AND f0_.username = :name2' 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE f0_.username = ? AND f0_.username = ?'
); );
} }
...@@ -107,7 +107,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ...@@ -107,7 +107,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
'select u from Doctrine\Tests\Models\Forum\ForumUser u where (u.username = :name OR u.username = :name2) AND u.id = :id', 'select u from Doctrine\Tests\Models\Forum\ForumUser u where (u.username = :name OR u.username = :name2) AND u.id = :id',
'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE (f0_.username = :name OR f0_.username = :name2) AND f0_.id = :id' 'SELECT f0_.id AS id0, f0_.username AS username1 FROM forum_users f0_ WHERE (f0_.username = ? OR f0_.username = ?) AND f0_.id = ?'
); );
} }
...@@ -244,7 +244,44 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ...@@ -244,7 +244,44 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
); );
} }
public function testExistsExpressionInWhereCorrelatedSubqueryAssocCondition() public function testMemberOfExpression()
{
// "Get all users who have $phone as a phonenumber." (*cough* doesnt really make sense...)
$q1 = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers');
$phone = new \Doctrine\Tests\Models\CMS\CmsPhonenumber;
$phone->phonenumber = 101;
$q1->setParameter('param', $phone);
$this->assertEquals(
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_phonenumbers c1_ WHERE c0_.id = c1_.user_id AND c1_.phonenumber = ?)',
$q1->getSql()
);
// "Get all users who are members of $group."
$q2 = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.groups');
$group = new \Doctrine\Tests\Models\CMS\CmsGroup;
$group->id = 101;
$q2->setParameter('param', $group);
$this->assertEquals(
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.user_id = c0_.id WHERE c1_.group_id = c2_.id AND c2_.id = ?)',
$q2->getSql()
);
// "Get all persons who have $person as a friend."
// Tough one: Many-many self-referencing ("friends") with class table inheritance
$q3 = $this->_em->createQuery('SELECT p.id FROM Doctrine\Tests\Models\Company\CompanyPerson p WHERE :param MEMBER OF p.friends');
$person = new \Doctrine\Tests\Models\Company\CompanyPerson;
$this->_em->getClassMetadata(get_class($person))->setIdentifierValues($person, 101);
$q3->setParameter('param', $person);
$this->assertEquals(
'SELECT c0_.id AS id0, c0_.discr AS discr1 FROM company_persons c0_ LEFT JOIN company_employees c1_ ON c0_.id = c1_.id LEFT JOIN company_managers c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.person_id = c0_.id WHERE c3_.friend_id = c4_.id AND c4_.id = ?)',
$q3->getSql()
);
}
/*public function testExistsExpressionInWhereCorrelatedSubqueryAssocCondition()
{ {
$this->assertSqlGeneration( $this->assertSqlGeneration(
// DQL // DQL
...@@ -261,5 +298,5 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ...@@ -261,5 +298,5 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
. ')' . ')'
); );
} }*/
} }
\ No newline at end of file
...@@ -67,6 +67,7 @@ class OrmFunctionalTestCase extends OrmTestCase ...@@ -67,6 +67,7 @@ class OrmFunctionalTestCase extends OrmTestCase
$conn->exec('DELETE FROM cms_users'); $conn->exec('DELETE FROM cms_users');
} }
if (isset($this->_usedModelSets['company'])) { if (isset($this->_usedModelSets['company'])) {
$conn->exec('DELETE FROM company_persons_friends');
$conn->exec('DELETE FROM company_managers'); $conn->exec('DELETE FROM company_managers');
$conn->exec('DELETE FROM company_employees'); $conn->exec('DELETE FROM company_employees');
$conn->exec('DELETE FROM company_persons'); $conn->exec('DELETE FROM company_persons');
...@@ -99,7 +100,7 @@ class OrmFunctionalTestCase extends OrmTestCase ...@@ -99,7 +100,7 @@ class OrmFunctionalTestCase extends OrmTestCase
$classes = array(); $classes = array();
foreach ($this->_usedModelSets as $setName => $bool) { foreach ($this->_usedModelSets as $setName => $bool) {
if ( ! isset(self::$_tablesCreated[$setName]) || $forceCreateTables) { if ( ! isset(self::$_tablesCreated[$setName])/* || $forceCreateTables*/) {
foreach (self::$_modelSets[$setName] as $className) { foreach (self::$_modelSets[$setName] as $className) {
$classes[] = $this->_em->getClassMetadata($className); $classes[] = $this->_em->getClassMetadata($className);
} }
......
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