Commit 10439800 authored by romanb's avatar romanb

[2.0] Parser work.

parent 84c62d8a
......@@ -33,7 +33,6 @@ use \ArrayIterator;
*
* @author Roman S. Borschel <roman@code-factory.org>
* @since 2.0
* @todo Consider extending ArrayObject
*/
class Collection implements Countable, IteratorAggregate, ArrayAccess
{
......@@ -310,6 +309,7 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
/**
* Checks whether the collection is empty.
*
* Note: This is preferrable over count() == 0.
*
* @return boolean TRUE if the collection is empty, FALSE otherwise.
......
......@@ -601,16 +601,16 @@ class Connection
if ($this->_config->getSqlLogger()) {
$this->_config->getSqlLogger()->logSql($query, $params);
}
if ( ! empty($params)) {
$stmt = $this->prepare($query);
$stmt = $this->_conn->prepare($query);
$stmt->execute($params);
return $stmt;
} else {
$stmt = $this->_conn->query($query);
$this->_queryCount++;
return $stmt;
}
$this->_queryCount++;
return $stmt;
}
/**
......@@ -630,14 +630,15 @@ class Connection
}
if ( ! empty($params)) {
$stmt = $this->prepare($query);
$stmt = $this->_conn->prepare($query);
$stmt->execute($params);
return $stmt->rowCount();
$result = $stmt->rowCount();
} else {
$count = $this->_conn->exec($query);
$this->_queryCount++;
return $count;
$result = $this->_conn->exec($query);
}
$this->_queryCount++;
return $result;
}
/**
......@@ -769,23 +770,6 @@ class Connection
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.
*
......
......@@ -1219,10 +1219,8 @@ abstract class AbstractPlatform
$item[$k] = (int) $value;
}
}
} else {
if (is_bool($item)) {
$item = (int) $item;
}
} else if (is_bool($item)) {
$item = (int) $item;
}
return $item;
}
......
......@@ -14,7 +14,7 @@ class BooleanType extends Type
*
* @override
*/
public function convertToDatabaseValue($value, Doctrine_DatabasePlatform $platform)
public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
{
return $platform->convertBooleans($value);
}
......@@ -24,7 +24,7 @@ class BooleanType extends Type
*
* @override
*/
public function convertToObjectValue($value)
public function convertToPHPValue($value)
{
return (bool) $value;
}
......
......@@ -178,19 +178,23 @@ abstract class AbstractQuery
*
* @return array Defined parameters
*/
public function getParams($params = array())
public function getParameters($params = array())
{
return array_merge($this->_params, $params);
if ($params) {
return array_merge($this->_params, $params);
}
return $this->_params;
}
/**
* setParams
*
* @param array $params
* Gets a query parameter.
*
* @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;
}
/**
......@@ -469,8 +473,8 @@ abstract class AbstractQuery
if ($hydrationMode !== null) {
$this->_hydrationMode = $hydrationMode;
}
$params = $this->getParams($params);
$params = $this->getParameters($params);
// Check result cache
if ($cacheDriver = $this->getResultCacheDriver()) {
......@@ -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)
{
return $this->_em->getConnection()->getDatabasePlatform()->convertBooleans($params);
}
abstract protected function _prepareParams(array $params);
/**
* Executes the query and returns a reference to the resulting Statement object.
......
......@@ -71,6 +71,7 @@ class DynamicProxyGenerator
require $fileName;
}
$proxyClassName = '\\' . self::$_ns . $proxyClassName;
return new $proxyClassName($this->_em, $class, $identifier);
}
......@@ -89,6 +90,7 @@ class DynamicProxyGenerator
require $fileName;
}
$proxyClassName = '\\' . self::$_ns . $proxyClassName;
return new $proxyClassName($this->_em, $assoc, $owner);
}
......
......@@ -858,6 +858,9 @@ final class ClassMetadata
/**
* 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
* @return mixed
......
......@@ -63,6 +63,9 @@ class ManyToManyMapping extends AssociationMapping
*/
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.
*
......
......@@ -42,24 +42,10 @@ namespace Doctrine\ORM\Mapping;
*/
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) */
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.
......
......@@ -74,4 +74,21 @@ final class NativeQuery extends AbstractQuery
{
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;
/**
* A PersistentCollection represents a collection of elements that have persistent state.
*
* 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
* entities from the collection, only the links in the relation table are removed (on flush).
......
......@@ -48,7 +48,7 @@ final class Query extends AbstractQuery
* parsed/processed. This is automatically defined as DIRTY when addDqlQueryPart
* is called.
*/
const STATE_DIRTY = 2;
const STATE_DIRTY = 2;
/**
* @var integer $_state The current state of this query.
......@@ -64,6 +64,16 @@ final class Query extends AbstractQuery
* @var Doctrine\ORM\Query\ParserResult The parser result that holds DQL => SQL information.
*/
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.
......@@ -100,7 +110,7 @@ final class Query extends AbstractQuery
*/
public function getSql()
{
return $this->parse()->getSqlExecutor()->getSqlStatements();
return $this->_parse()->getSqlExecutor()->getSqlStatements();
}
/**
......@@ -110,7 +120,7 @@ final class Query extends AbstractQuery
*
* @return Doctrine\ORM\Query\ParserResult
*/
public function parse()
private function _parse()
{
if ($this->_state === self::STATE_DIRTY) {
$parser = new Parser($this);
......@@ -121,15 +131,15 @@ final class Query extends AbstractQuery
}
/**
* _execute
* {@inheritdoc}
*
* @param array $params
* @return PDOStatement The executed PDOStatement.
* @return Statement The resulting Statement.
* @override
*/
protected function _doExecute(array $params)
{
// If there is a CacheDriver associated to cache queries...
// Check query cache
if ($queryCache = $this->getQueryCacheDriver()) {
// Calculate hash for dql query.
$hash = md5($this->getDql() . 'DOCTRINE_QUERY_CACHE_SALT');
......@@ -137,7 +147,7 @@ final class Query extends AbstractQuery
if ($cached === false) {
// Cache miss.
$executor = $this->parse()->getSqlExecutor();
$executor = $this->_parse()->getSqlExecutor();
$queryCache->save($hash, serialize($this->_parserResult), null);
} else {
// Cache hit.
......@@ -145,19 +155,48 @@ final class Query extends AbstractQuery
$executor = $this->_parserResult->getSqlExecutor();
}
} else {
$executor = $this->parse()->getSqlExecutor();
$executor = $this->_parse()->getSqlExecutor();
}
// Converting parameters
$params = $this->_prepareParams($params);
if ( ! $this->_resultSetMapping) {
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
}
// Executing the query and returning statement
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.
......@@ -292,6 +331,52 @@ final class Query extends AbstractQuery
*/
public function contains($dql)
{
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;
/**
* "ABS" "(" SimpleArithmeticExpression ")"
*
* @author robo
* @author Roman Borschel <roman@code-factory.org>
*/
class AbsFunction extends FunctionNode
{
......@@ -37,7 +37,7 @@ class AbsFunction extends FunctionNode
$lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']);
$parser->match('(');
$this->_simpleArithmeticExpression = $parser->_SimpleArithmeticExpression();
$this->_simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(')');
}
}
......
......@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions;
/**
* "CONCAT" "(" StringPrimary "," StringPrimary ")"
*
* @author robo
* @author Roman Borschel <roman@code-factory.org>
*/
class ConcatFunction extends FunctionNode
{
......@@ -36,13 +36,6 @@ class ConcatFunction extends FunctionNode
$sqlWalker->walkStringPrimary($this->_firstStringPrimary),
$sqlWalker->walkStringPrimary($this->_secondStringPrimary)
);
/*
$sql = 'CONCAT(' .
$sqlWalker->walkStringPrimary($this->_firstStringPrimary)
. ', ' .
$sqlWalker->walkStringPrimary($this->_secondStringPrimary)
. ')';
return $sql;*/
}
/**
......@@ -54,9 +47,9 @@ class ConcatFunction extends FunctionNode
$parser->match($lexer->lookahead['value']);
$parser->match('(');
$this->_firstStringPrimary = $parser->_StringPrimary();
$this->_firstStringPrimary = $parser->StringPrimary();
$parser->match(',');
$this->_secondStringPrimary = $parser->_StringPrimary();
$this->_secondStringPrimary = $parser->StringPrimary();
$parser->match(')');
}
......
......@@ -31,7 +31,6 @@ use Doctrine\ORM\Query\AST\Node;
abstract class FunctionNode extends Node
{
private $_name;
//private $_expressions = array();
public function __construct($name)
{
......
......@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions;
/**
* "LENGTH" "(" StringPrimary ")"
*
* @author robo
* @author Roman Borschel <roman@code-factory.org>
*/
class LengthFunction extends FunctionNode
{
......@@ -37,7 +37,7 @@ class LengthFunction extends FunctionNode
$lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']);
$parser->match('(');
$this->_stringPrimary = $parser->_StringPrimary();
$this->_stringPrimary = $parser->StringPrimary();
$parser->match(')');
}
}
......
......@@ -57,12 +57,12 @@ class LocateFunction extends FunctionNode
$lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']);
$parser->match('(');
$this->_firstStringPrimary = $parser->_StringPrimary();
$this->_firstStringPrimary = $parser->StringPrimary();
$parser->match(',');
$this->_secondStringPrimary = $parser->_StringPrimary();
$this->_secondStringPrimary = $parser->StringPrimary();
if ($lexer->isNextToken(',')) {
$parser->match(',');
$this->_simpleArithmeticExpression = $parser->_SimpleArithmeticExpression();
$this->_simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
}
$parser->match(')');
}
......
......@@ -37,7 +37,7 @@ class LowerFunction extends FunctionNode
$lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']);
$parser->match('(');
$this->_stringPrimary = $parser->_StringPrimary();
$this->_stringPrimary = $parser->StringPrimary();
$parser->match(')');
}
}
......
......@@ -47,9 +47,9 @@ class ModFunction extends FunctionNode
$lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']);
$parser->match('(');
$this->_firstSimpleArithmeticExpression = $parser->_SimpleArithmeticExpression();
$this->_firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(',');
$this->_secondSimpleArithmeticExpression = $parser->_SimpleArithmeticExpression();
$this->_secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(')');
}
}
......
......@@ -37,7 +37,7 @@ class SizeFunction extends FunctionNode
$lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']);
$parser->match('(');
$this->_collectionPathExpression = $parser->_CollectionValuedPathExpression();
$this->_collectionPathExpression = $parser->CollectionValuedPathExpression();
$parser->match(')');
}
}
......
......@@ -9,7 +9,7 @@ namespace Doctrine\ORM\Query\AST\Functions;
/**
* "SQRT" "(" SimpleArithmeticExpression ")"
*
* @author robo
* @author Roman Borschel <roman@code-factory.org>
*/
class SqrtFunction extends FunctionNode
{
......@@ -37,7 +37,7 @@ class SqrtFunction extends FunctionNode
$lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']);
$parser->match('(');
$this->_simpleArithmeticExpression = $parser->_SimpleArithmeticExpression();
$this->_simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(')');
}
}
......
......@@ -57,11 +57,11 @@ class SubstringFunction extends FunctionNode
$parser->match($lexer->lookahead['value']);
$parser->match('(');
$this->_stringPrimary = $parser->_StringPrimary();
$this->_stringPrimary = $parser->StringPrimary();
$parser->match(',');
$this->_firstSimpleArithmeticExpression = $parser->_SimpleArithmeticExpression();
$this->_firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(',');
$this->_secondSimpleArithmeticExpression = $parser->_SimpleArithmeticExpression();
$this->_secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(')');
}
......
......@@ -75,7 +75,7 @@ class TrimFunction extends FunctionNode
if ($this->_leading) $sql .= 'LEADING ';
else if ($this->_trailing) $sql .= 'TRAILING ';
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 .= ')';
return $sql;
......@@ -110,7 +110,7 @@ class TrimFunction extends FunctionNode
$parser->match(Lexer::T_FROM);
}
$this->_stringPrimary = $parser->_StringPrimary();
$this->_stringPrimary = $parser->StringPrimary();
$parser->match(')');
}
......
......@@ -37,7 +37,7 @@ class UpperFunction extends FunctionNode
$lexer = $parser->getLexer();
$parser->match($lexer->lookahead['value']);
$parser->match('(');
$this->_stringPrimary = $parser->_StringPrimary();
$this->_stringPrimary = $parser->StringPrimary();
$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
const T_WITH = 145;
const T_TRUE = 146;
const T_FALSE = 147;
const T_MEMBER = 148;
const T_OF = 149;
private $_keywordsTable;
......@@ -131,8 +133,8 @@ class Lexer
/**
* Checks whether a given token matches the current lookahead.
*
* @param <type> $token
* @return <type>
* @param integer|string $token
* @return boolean
*/
public function isNextToken($token)
{
......@@ -170,7 +172,7 @@ class Lexer
* @param string $identifier identifier name
* @return int token type
*/
public function _checkLiteral($identifier)
private function _checkLiteral($identifier)
{
$name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($identifier);
......@@ -237,6 +239,7 @@ class Lexer
}
if ($value[0] === "'" && $value[strlen($value) - 1] === "'") {
$type = self::T_STRING;
$value = str_replace("''", "'", substr($value, 1, strlen($value) - 2));
} else if (ctype_alpha($value[0]) || $value[0] === '_') {
$type = $this->_checkLiteral($value);
} else if ($value[0] === '?' || $value[0] === ':') {
......
This diff is collapsed.
......@@ -35,8 +35,12 @@ namespace Doctrine\ORM\Query;
*/
class ParserResult
{
/** The SQL executor used for executing the SQL. */
private $_sqlExecutor;
/** The ResultSetMapping that describes how to map the SQL result set. */
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.
......@@ -87,4 +91,37 @@ class ParserResult
{
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
if (isset($class->inheritedAssociationFields[$fieldName])) {
continue;
}
$foreignClass = $this->_em->getClassMetadata($mapping->targetEntityName);
if ($mapping->isOneToOne() && $mapping->isOwningSide) {
$constraint = array();
......
......@@ -403,12 +403,14 @@ class UnitOfWork implements PropertyChangedListener
&& $actualData[$name] !== null
&& ! ($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];
//echo PHP_EOL . "INJECTING PCOLL into $name" . PHP_EOL;
// Inject PersistentCollection
$coll = new PersistentCollection($this->_em, $this->_em->getClassMetadata($assoc->targetEntityName),
$actualData[$name] ? $actualData[$name] : array());
$actualData[$name] ? $actualData[$name] : array());
$coll->setOwner($entity, $assoc);
if ( ! $coll->isEmpty()) {
$coll->setDirty(true);
......
......@@ -19,9 +19,9 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase
{
$this->_coll->add("one");
$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);
$exists = $this->_coll->exists(function($key, $element) { return $element == "other"; });
$exists = $this->_coll->exists(function($k, $e) { return $e == "other"; });
$this->assertFalse($exists);
}
......@@ -29,7 +29,7 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase
{
$this->_coll->add(1);
$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());
}
......@@ -38,7 +38,7 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase
$this->_coll->add(1);
$this->_coll->add("foo");
$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());
}
......@@ -66,39 +66,39 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase
public function testContainsKey()
{
$this->_coll[5] = 'five';
$this->assertEquals($this->_coll->containsKey(5), true);
$this->assertTrue($this->_coll->containsKey(5));
}
public function testContains()
{
$this->_coll[0] = 'test';
$this->assertEquals($this->_coll->contains('test'), true);
$this->assertTrue($this->_coll->contains('test'));
}
public function testSearch()
{
$this->_coll[0] = 'test';
$this->assertEquals($this->_coll->search('test'), 0);
$this->assertEquals(0, $this->_coll->search('test'));
}
public function testGet()
{
$this->_coll[0] = 'test';
$this->assertEquals($this->_coll->get(0), 'test');
$this->assertEquals('test', $this->_coll->get(0));
}
public function testGetKeys()
{
$this->_coll[] = 'one';
$this->_coll[] = 'two';
$this->assertEquals($this->_coll->getKeys(), array(0, 1));
$this->assertEquals(array(0, 1), $this->_coll->getKeys());
}
public function testGetElements()
{
$this->_coll[] = 'one';
$this->_coll[] = 'two';
$this->assertEquals($this->_coll->getElements(), array('one', 'two'));
$this->assertEquals(array('one', 'two'), $this->_coll->getElements());
}
public function testCount()
......@@ -113,15 +113,15 @@ class CollectionTest extends \Doctrine\Tests\DoctrineTestCase
{
$this->_coll[] = 'one';
$this->_coll[] = 'two';
$this->assertEquals($this->_coll->forAll(function($key, $element) { return is_string($element); }), true);
$this->assertEquals($this->_coll->forAll(function($key, $element) { return is_array($element); }), false);
$this->assertEquals($this->_coll->forAll(function($k, $e) { return is_string($e); }), true);
$this->assertEquals($this->_coll->forAll(function($k, $e) { return is_array($e); }), false);
}
public function testPartition()
{
$this->_coll[] = true;
$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[1][0], false);
}
......
......@@ -53,7 +53,7 @@ class ConnectionMock extends \Doctrine\DBAL\Connection
*/
public function quote($input, $type = null)
{
if ($type === 'string') {
if (is_string($input)) {
return "'" . $input . "'";
}
return $input;
......
<?php
namespace Doctrine\Tests\Mocks;
class MockTreeWalker extends \Doctrine\ORM\Query\TreeWalkerAdapter
{
}
......@@ -31,6 +31,14 @@ class CompanyPerson
* @JoinColumn(name="spouse_id", referencedColumnName="id")
*/
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() {
return $this->id;
......@@ -47,6 +55,20 @@ class CompanyPerson
public function getSpouse() {
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) {
if ($spouse !== $this->spouse) {
......
......@@ -65,28 +65,6 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(100000, $entities[0]->getSalary());
$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() {
......@@ -149,4 +127,37 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals('John Smith', $result[0]->getSpouse()->getName());
$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
{
try {
$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) {
if ($debug) {
echo $e->getTraceAsString() . PHP_EOL;
......@@ -30,15 +32,15 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
try {
$query = $this->_em->createQuery($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');
} catch (\Exception $e) {
//echo $e->getMessage() . PHP_EOL;
if ($debug) {
echo $e->getMessage() . PHP_EOL;
echo $e->getTraceAsString() . PHP_EOL;
}
// It was expected!
}
}
......@@ -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)');
}
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
$lexer->moveNext();
$token = $lexer->lookahead;
$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()
......@@ -191,7 +191,7 @@ class LexerTest extends \Doctrine\Tests\OrmTestCase
$lexer->moveNext();
$token = $lexer->lookahead;
$this->assertEquals(Lexer::T_STRING, $token['type']);
$this->assertEquals("'abc''defg'''", $token['value']);
$this->assertEquals("abc'defg'", $token['value']);
}
public function testScannerRecognizesInputParameter()
......@@ -269,7 +269,7 @@ class LexerTest extends \Doctrine\Tests\OrmTestCase
'position' => 47
),
array(
'value' => "'Jack O''Neil'",
'value' => "Jack O'Neil",
'type' => Lexer::T_STRING,
'position' => 49
)
......
......@@ -21,7 +21,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$query->free();
} catch (Doctrine_Exception $e) {
echo $e->getMessage();
echo $e->getTraceAsString(); die();
echo $e->getTraceAsString();
$this->fail($e->getMessage());
}
}
......@@ -91,7 +91,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{
$this->assertSqlGeneration(
'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
{
$this->assertSqlGeneration(
'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
{
$this->assertSqlGeneration(
'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 = ?'
);
}
......@@ -243,8 +243,45 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT c1_.phonenumber FROM cms_phonenumbers c1_ WHERE c1_.phonenumber = c0_.id)'
);
}
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()
/*public function testExistsExpressionInWhereCorrelatedSubqueryAssocCondition()
{
$this->assertSqlGeneration(
// DQL
......@@ -261,5 +298,5 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
. ')'
);
}
}*/
}
\ No newline at end of file
......@@ -67,6 +67,7 @@ class OrmFunctionalTestCase extends OrmTestCase
$conn->exec('DELETE FROM cms_users');
}
if (isset($this->_usedModelSets['company'])) {
$conn->exec('DELETE FROM company_persons_friends');
$conn->exec('DELETE FROM company_managers');
$conn->exec('DELETE FROM company_employees');
$conn->exec('DELETE FROM company_persons');
......@@ -99,7 +100,7 @@ class OrmFunctionalTestCase extends OrmTestCase
$classes = array();
foreach ($this->_usedModelSets as $setName => $bool) {
if ( ! isset(self::$_tablesCreated[$setName]) || $forceCreateTables) {
if ( ! isset(self::$_tablesCreated[$setName])/* || $forceCreateTables*/) {
foreach (self::$_modelSets[$setName] as $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