welcome back to dyb-tech
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
|
||||
use function get_debug_type;
|
||||
|
||||
/**
|
||||
* Base exception class for AST exceptions.
|
||||
*/
|
||||
class ASTException extends QueryException
|
||||
{
|
||||
/**
|
||||
* @param Node $node
|
||||
*
|
||||
* @return ASTException
|
||||
*/
|
||||
public static function noDispatchForNode($node)
|
||||
{
|
||||
return new self('Double-dispatch for node ' . get_debug_type($node) . ' is not supported.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
class AggregateExpression extends Node
|
||||
{
|
||||
/** @var string */
|
||||
public $functionName;
|
||||
|
||||
/** @var PathExpression|SimpleArithmeticExpression */
|
||||
public $pathExpression;
|
||||
|
||||
/**
|
||||
* Some aggregate expressions support distinct, eg COUNT.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $isDistinct = false;
|
||||
|
||||
/**
|
||||
* @param string $functionName
|
||||
* @param PathExpression|SimpleArithmeticExpression $pathExpression
|
||||
* @param bool $isDistinct
|
||||
*/
|
||||
public function __construct($functionName, $pathExpression, $isDistinct)
|
||||
{
|
||||
$this->functionName = $functionName;
|
||||
$this->pathExpression = $pathExpression;
|
||||
$this->isDistinct = $isDistinct;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkAggregateExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ArithmeticExpression extends Node
|
||||
{
|
||||
/** @var SimpleArithmeticExpression|null */
|
||||
public $simpleArithmeticExpression;
|
||||
|
||||
/** @var Subselect|null */
|
||||
public $subselect;
|
||||
|
||||
/** @return bool */
|
||||
public function isSimpleArithmeticExpression()
|
||||
{
|
||||
return (bool) $this->simpleArithmeticExpression;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function isSubselect()
|
||||
{
|
||||
return (bool) $this->subselect;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkArithmeticExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ArithmeticFactor extends Node
|
||||
{
|
||||
/** @var mixed */
|
||||
public $arithmeticPrimary;
|
||||
|
||||
/**
|
||||
* NULL represents no sign, TRUE means positive and FALSE means negative sign.
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
public $sign;
|
||||
|
||||
/**
|
||||
* @param mixed $arithmeticPrimary
|
||||
* @param bool|null $sign
|
||||
*/
|
||||
public function __construct($arithmeticPrimary, $sign = null)
|
||||
{
|
||||
$this->arithmeticPrimary = $arithmeticPrimary;
|
||||
$this->sign = $sign;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function isPositiveSigned()
|
||||
{
|
||||
return $this->sign === true;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function isNegativeSigned()
|
||||
{
|
||||
return $this->sign === false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkArithmeticFactor($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ArithmeticTerm extends Node
|
||||
{
|
||||
/** @var mixed[] */
|
||||
public $arithmeticFactors;
|
||||
|
||||
/** @param mixed[] $arithmeticFactors */
|
||||
public function __construct(array $arithmeticFactors)
|
||||
{
|
||||
$this->arithmeticFactors = $arithmeticFactors;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkArithmeticTerm($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
class BetweenExpression extends Node
|
||||
{
|
||||
/** @var ArithmeticExpression */
|
||||
public $expression;
|
||||
|
||||
/** @var ArithmeticExpression */
|
||||
public $leftBetweenExpression;
|
||||
|
||||
/** @var ArithmeticExpression */
|
||||
public $rightBetweenExpression;
|
||||
|
||||
/** @var bool */
|
||||
public $not;
|
||||
|
||||
/**
|
||||
* @param ArithmeticExpression $expr
|
||||
* @param ArithmeticExpression $leftExpr
|
||||
* @param ArithmeticExpression $rightExpr
|
||||
*/
|
||||
public function __construct($expr, $leftExpr, $rightExpr, bool $not = false)
|
||||
{
|
||||
$this->expression = $expr;
|
||||
$this->leftBetweenExpression = $leftExpr;
|
||||
$this->rightBetweenExpression = $rightExpr;
|
||||
$this->not = $not;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkBetweenExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class CoalesceExpression extends Node
|
||||
{
|
||||
/** @var mixed[] */
|
||||
public $scalarExpressions = [];
|
||||
|
||||
/** @param mixed[] $scalarExpressions */
|
||||
public function __construct(array $scalarExpressions)
|
||||
{
|
||||
$this->scalarExpressions = $scalarExpressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkCoalesceExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class CollectionMemberExpression extends Node
|
||||
{
|
||||
/** @var mixed */
|
||||
public $entityExpression;
|
||||
|
||||
/** @var PathExpression */
|
||||
public $collectionValuedPathExpression;
|
||||
|
||||
/** @var bool */
|
||||
public $not;
|
||||
|
||||
/**
|
||||
* @param mixed $entityExpr
|
||||
* @param PathExpression $collValuedPathExpr
|
||||
*/
|
||||
public function __construct($entityExpr, $collValuedPathExpr, bool $not = false)
|
||||
{
|
||||
$this->entityExpression = $entityExpr;
|
||||
$this->collectionValuedPathExpression = $collValuedPathExpr;
|
||||
$this->not = $not;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkCollectionMemberExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression ) |
|
||||
* StringExpression ComparisonOperator (StringExpression | QuantifiedExpression) |
|
||||
* BooleanExpression ("=" | "<>" | "!=") (BooleanExpression | QuantifiedExpression) |
|
||||
* EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) |
|
||||
* DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) |
|
||||
* EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression)
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ComparisonExpression extends Node
|
||||
{
|
||||
/** @var Node|string */
|
||||
public $leftExpression;
|
||||
|
||||
/** @var Node|string */
|
||||
public $rightExpression;
|
||||
|
||||
/** @var string */
|
||||
public $operator;
|
||||
|
||||
/**
|
||||
* @param Node|string $leftExpr
|
||||
* @param string $operator
|
||||
* @param Node|string $rightExpr
|
||||
*/
|
||||
public function __construct($leftExpr, $operator, $rightExpr)
|
||||
{
|
||||
$this->leftExpression = $leftExpr;
|
||||
$this->rightExpression = $rightExpr;
|
||||
$this->operator = $operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkComparisonExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ConditionalExpression extends Node
|
||||
{
|
||||
/** @var mixed[] */
|
||||
public $conditionalTerms = [];
|
||||
|
||||
/** @param mixed[] $conditionalTerms */
|
||||
public function __construct(array $conditionalTerms)
|
||||
{
|
||||
$this->conditionalTerms = $conditionalTerms;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkConditionalExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ConditionalFactor ::= ["NOT"] ConditionalPrimary
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ConditionalFactor extends Node implements Phase2OptimizableConditional
|
||||
{
|
||||
/** @var bool */
|
||||
public $not = false;
|
||||
|
||||
/** @var ConditionalPrimary */
|
||||
public $conditionalPrimary;
|
||||
|
||||
/** @param ConditionalPrimary $conditionalPrimary */
|
||||
public function __construct($conditionalPrimary, bool $not = false)
|
||||
{
|
||||
$this->conditionalPrimary = $conditionalPrimary;
|
||||
$this->not = $not;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkConditionalFactor($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ConditionalPrimary extends Node implements Phase2OptimizableConditional
|
||||
{
|
||||
/** @var Node|null */
|
||||
public $simpleConditionalExpression;
|
||||
|
||||
/** @var ConditionalExpression|Phase2OptimizableConditional|null */
|
||||
public $conditionalExpression;
|
||||
|
||||
/** @return bool */
|
||||
public function isSimpleConditionalExpression()
|
||||
{
|
||||
return (bool) $this->simpleConditionalExpression;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function isConditionalExpression()
|
||||
{
|
||||
return (bool) $this->conditionalExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkConditionalPrimary($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ConditionalTerm extends Node implements Phase2OptimizableConditional
|
||||
{
|
||||
/** @var mixed[] */
|
||||
public $conditionalFactors = [];
|
||||
|
||||
/** @param mixed[] $conditionalFactors */
|
||||
public function __construct(array $conditionalFactors)
|
||||
{
|
||||
$this->conditionalFactors = $conditionalFactors;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkConditionalTerm($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName [["AS"] AliasIdentificationVariable]
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class DeleteClause extends Node
|
||||
{
|
||||
/** @var string */
|
||||
public $abstractSchemaName;
|
||||
|
||||
/** @var string */
|
||||
public $aliasIdentificationVariable;
|
||||
|
||||
/** @param string $abstractSchemaName */
|
||||
public function __construct($abstractSchemaName)
|
||||
{
|
||||
$this->abstractSchemaName = $abstractSchemaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkDeleteClause($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* DeleteStatement = DeleteClause [WhereClause]
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class DeleteStatement extends Node
|
||||
{
|
||||
/** @var DeleteClause */
|
||||
public $deleteClause;
|
||||
|
||||
/** @var WhereClause|null */
|
||||
public $whereClause;
|
||||
|
||||
/** @param DeleteClause $deleteClause */
|
||||
public function __construct($deleteClause)
|
||||
{
|
||||
$this->deleteClause = $deleteClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkDeleteStatement($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class EmptyCollectionComparisonExpression extends Node
|
||||
{
|
||||
/** @var PathExpression */
|
||||
public $expression;
|
||||
|
||||
/** @var bool */
|
||||
public $not;
|
||||
|
||||
/** @param PathExpression $expression */
|
||||
public function __construct($expression, bool $not = false)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
$this->not = $not;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkEmptyCollectionComparisonExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ExistsExpression extends Node
|
||||
{
|
||||
/** @var bool */
|
||||
public $not;
|
||||
|
||||
/** @var Subselect */
|
||||
public $subselect;
|
||||
|
||||
/** @param Subselect $subselect */
|
||||
public function __construct($subselect, bool $not = false)
|
||||
{
|
||||
$this->subselect = $subselect;
|
||||
$this->not = $not;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkExistsExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class FromClause extends Node
|
||||
{
|
||||
/** @var mixed[] */
|
||||
public $identificationVariableDeclarations = [];
|
||||
|
||||
/** @param mixed[] $identificationVariableDeclarations */
|
||||
public function __construct(array $identificationVariableDeclarations)
|
||||
{
|
||||
$this->identificationVariableDeclarations = $identificationVariableDeclarations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkFromClause($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\SimpleArithmeticExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "ABS" "(" SimpleArithmeticExpression ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class AbsFunction extends FunctionNode
|
||||
{
|
||||
/** @var SimpleArithmeticExpression */
|
||||
public $simpleArithmeticExpression;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return 'ABS(' . $sqlWalker->walkSimpleArithmeticExpression(
|
||||
$this->simpleArithmeticExpression
|
||||
) . ')';
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\AggregateExpression;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "AVG" "(" ["DISTINCT"] StringPrimary ")"
|
||||
*/
|
||||
final class AvgFunction extends FunctionNode
|
||||
{
|
||||
/** @var AggregateExpression */
|
||||
private $aggregateExpression;
|
||||
|
||||
public function getSql(SqlWalker $sqlWalker): string
|
||||
{
|
||||
return $this->aggregateExpression->dispatch($sqlWalker);
|
||||
}
|
||||
|
||||
public function parse(Parser $parser): void
|
||||
{
|
||||
$this->aggregateExpression = $parser->AggregateExpression();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "BIT_AND" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class BitAndFunction extends FunctionNode
|
||||
{
|
||||
/** @var Node */
|
||||
public $firstArithmetic;
|
||||
|
||||
/** @var Node */
|
||||
public $secondArithmetic;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
|
||||
|
||||
return $platform->getBitAndComparisonExpression(
|
||||
$this->firstArithmetic->dispatch($sqlWalker),
|
||||
$this->secondArithmetic->dispatch($sqlWalker)
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstArithmetic = $parser->ArithmeticPrimary();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$this->secondArithmetic = $parser->ArithmeticPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "BIT_OR" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class BitOrFunction extends FunctionNode
|
||||
{
|
||||
/** @var Node */
|
||||
public $firstArithmetic;
|
||||
|
||||
/** @var Node */
|
||||
public $secondArithmetic;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
|
||||
|
||||
return $platform->getBitOrComparisonExpression(
|
||||
$this->firstArithmetic->dispatch($sqlWalker),
|
||||
$this->secondArithmetic->dispatch($sqlWalker)
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstArithmetic = $parser->ArithmeticPrimary();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$this->secondArithmetic = $parser->ArithmeticPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "CONCAT" "(" StringPrimary "," StringPrimary {"," StringPrimary }* ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ConcatFunction extends FunctionNode
|
||||
{
|
||||
/** @var Node */
|
||||
public $firstStringPrimary;
|
||||
|
||||
/** @var Node */
|
||||
public $secondStringPrimary;
|
||||
|
||||
/** @psalm-var list<Node> */
|
||||
public $concatExpressions = [];
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
|
||||
|
||||
$args = [];
|
||||
|
||||
foreach ($this->concatExpressions as $expression) {
|
||||
$args[] = $sqlWalker->walkStringPrimary($expression);
|
||||
}
|
||||
|
||||
return $platform->getConcatExpression(...$args);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstStringPrimary = $parser->StringPrimary();
|
||||
$this->concatExpressions[] = $this->firstStringPrimary;
|
||||
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
|
||||
$this->secondStringPrimary = $parser->StringPrimary();
|
||||
$this->concatExpressions[] = $this->secondStringPrimary;
|
||||
|
||||
while ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$this->concatExpressions[] = $parser->StringPrimary();
|
||||
}
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Query\AST\AggregateExpression;
|
||||
use Doctrine\ORM\Query\AST\TypedExpression;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "COUNT" "(" ["DISTINCT"] StringPrimary ")"
|
||||
*/
|
||||
final class CountFunction extends FunctionNode implements TypedExpression
|
||||
{
|
||||
/** @var AggregateExpression */
|
||||
private $aggregateExpression;
|
||||
|
||||
public function getSql(SqlWalker $sqlWalker): string
|
||||
{
|
||||
return $this->aggregateExpression->dispatch($sqlWalker);
|
||||
}
|
||||
|
||||
public function parse(Parser $parser): void
|
||||
{
|
||||
$this->aggregateExpression = $parser->AggregateExpression();
|
||||
}
|
||||
|
||||
public function getReturnType(): Type
|
||||
{
|
||||
return Type::getType(Types::INTEGER);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "CURRENT_DATE"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class CurrentDateFunction extends FunctionNode
|
||||
{
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getCurrentDateSQL();
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "CURRENT_TIME"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class CurrentTimeFunction extends FunctionNode
|
||||
{
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getCurrentTimeSQL();
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "CURRENT_TIMESTAMP"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class CurrentTimestampFunction extends FunctionNode
|
||||
{
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getCurrentTimestampSQL();
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* "DATE_ADD" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class DateAddFunction extends FunctionNode
|
||||
{
|
||||
/** @var Node */
|
||||
public $firstDateExpression = null;
|
||||
|
||||
/** @var Node */
|
||||
public $intervalExpression = null;
|
||||
|
||||
/** @var Node */
|
||||
public $unit = null;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
switch (strtolower($this->unit->value)) {
|
||||
case 'second':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddSecondsExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'minute':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddMinutesExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'hour':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddHourExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'day':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddDaysExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'week':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddWeeksExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'month':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddMonthExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'year':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddYearsExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
default:
|
||||
throw QueryException::semanticalError(
|
||||
'DATE_ADD() only supports units of type second, minute, hour, day, week, month and year.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstDateExpression = $parser->ArithmeticPrimary();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$this->intervalExpression = $parser->ArithmeticPrimary();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$this->unit = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "DATE_DIFF" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class DateDiffFunction extends FunctionNode
|
||||
{
|
||||
/** @var Node */
|
||||
public $date1;
|
||||
|
||||
/** @var Node */
|
||||
public $date2;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateDiffExpression(
|
||||
$this->date1->dispatch($sqlWalker),
|
||||
$this->date2->dispatch($sqlWalker)
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->date1 = $parser->ArithmeticPrimary();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$this->date2 = $parser->ArithmeticPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
use function strtolower;
|
||||
|
||||
/**
|
||||
* "DATE_SUB(date1, interval, unit)"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class DateSubFunction extends DateAddFunction
|
||||
{
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
switch (strtolower($this->unit->value)) {
|
||||
case 'second':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubSecondsExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'minute':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubMinutesExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'hour':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubHourExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'day':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubDaysExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'week':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubWeeksExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'month':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubMonthExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
case 'year':
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubYearsExpression(
|
||||
$this->firstDateExpression->dispatch($sqlWalker),
|
||||
$this->intervalExpression->dispatch($sqlWalker)
|
||||
);
|
||||
|
||||
default:
|
||||
throw QueryException::semanticalError(
|
||||
'DATE_SUB() only supports units of type second, minute, hour, day, week, month and year.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* Abstract Function Node.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @psalm-consistent-constructor
|
||||
*/
|
||||
abstract class FunctionNode extends Node
|
||||
{
|
||||
/** @var string */
|
||||
public $name;
|
||||
|
||||
/** @param string $name */
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
abstract public function getSql(SqlWalker $sqlWalker);
|
||||
|
||||
/**
|
||||
* @param SqlWalker $sqlWalker
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkFunction($this);
|
||||
}
|
||||
|
||||
/** @return void */
|
||||
abstract public function parse(Parser $parser);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\PathExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
use function assert;
|
||||
use function reset;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* "IDENTITY" "(" SingleValuedAssociationPathExpression {"," string} ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class IdentityFunction extends FunctionNode
|
||||
{
|
||||
/** @var PathExpression */
|
||||
public $pathExpression;
|
||||
|
||||
/** @var string|null */
|
||||
public $fieldMapping;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
assert($this->pathExpression->field !== null);
|
||||
$entityManager = $sqlWalker->getEntityManager();
|
||||
$platform = $entityManager->getConnection()->getDatabasePlatform();
|
||||
$quoteStrategy = $entityManager->getConfiguration()->getQuoteStrategy();
|
||||
$dqlAlias = $this->pathExpression->identificationVariable;
|
||||
$assocField = $this->pathExpression->field;
|
||||
$assoc = $sqlWalker->getMetadataForDqlAlias($dqlAlias)->associationMappings[$assocField];
|
||||
$targetEntity = $entityManager->getClassMetadata($assoc['targetEntity']);
|
||||
$joinColumn = reset($assoc['joinColumns']);
|
||||
|
||||
if ($this->fieldMapping !== null) {
|
||||
if (! isset($targetEntity->fieldMappings[$this->fieldMapping])) {
|
||||
throw new QueryException(sprintf('Undefined reference field mapping "%s"', $this->fieldMapping));
|
||||
}
|
||||
|
||||
$field = $targetEntity->fieldMappings[$this->fieldMapping];
|
||||
$joinColumn = null;
|
||||
|
||||
foreach ($assoc['joinColumns'] as $mapping) {
|
||||
if ($mapping['referencedColumnName'] === $field['columnName']) {
|
||||
$joinColumn = $mapping;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($joinColumn === null) {
|
||||
throw new QueryException(sprintf('Unable to resolve the reference field mapping "%s"', $this->fieldMapping));
|
||||
}
|
||||
}
|
||||
|
||||
// The table with the relation may be a subclass, so get the table name from the association definition
|
||||
$tableName = $entityManager->getClassMetadata($assoc['sourceEntity'])->getTableName();
|
||||
|
||||
$tableAlias = $sqlWalker->getSQLTableAlias($tableName, $dqlAlias);
|
||||
$columnName = $quoteStrategy->getJoinColumnName($joinColumn, $targetEntity, $platform);
|
||||
|
||||
return $tableAlias . '.' . $columnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->pathExpression = $parser->SingleValuedAssociationPathExpression();
|
||||
|
||||
if ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$parser->match(Lexer::T_STRING);
|
||||
|
||||
$token = $parser->getLexer()->token;
|
||||
assert($token !== null);
|
||||
$this->fieldMapping = $token->value;
|
||||
}
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\AST\TypedExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "LENGTH" "(" StringPrimary ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class LengthFunction extends FunctionNode implements TypedExpression
|
||||
{
|
||||
/** @var Node */
|
||||
public $stringPrimary;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getLengthExpression(
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary)
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->stringPrimary = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
|
||||
public function getReturnType(): Type
|
||||
{
|
||||
return Type::getType(Types::INTEGER);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\AST\SimpleArithmeticExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class LocateFunction extends FunctionNode
|
||||
{
|
||||
/** @var Node */
|
||||
public $firstStringPrimary;
|
||||
|
||||
/** @var Node */
|
||||
public $secondStringPrimary;
|
||||
|
||||
/** @var SimpleArithmeticExpression|bool */
|
||||
public $simpleArithmeticExpression = false;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
|
||||
|
||||
$firstString = $sqlWalker->walkStringPrimary($this->firstStringPrimary);
|
||||
$secondString = $sqlWalker->walkStringPrimary($this->secondStringPrimary);
|
||||
|
||||
if ($this->simpleArithmeticExpression) {
|
||||
return $platform->getLocateExpression(
|
||||
$secondString,
|
||||
$firstString,
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->simpleArithmeticExpression)
|
||||
);
|
||||
}
|
||||
|
||||
return $platform->getLocateExpression($secondString, $firstString);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstStringPrimary = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
|
||||
$this->secondStringPrimary = $parser->StringPrimary();
|
||||
|
||||
$lexer = $parser->getLexer();
|
||||
if ($lexer->isNextToken(Lexer::T_COMMA)) {
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
|
||||
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
}
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* "LOWER" "(" StringPrimary ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class LowerFunction extends FunctionNode
|
||||
{
|
||||
/** @var Node */
|
||||
public $stringPrimary;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return sprintf(
|
||||
'LOWER(%s)',
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary)
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->stringPrimary = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\AggregateExpression;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "MAX" "(" ["DISTINCT"] StringPrimary ")"
|
||||
*/
|
||||
final class MaxFunction extends FunctionNode
|
||||
{
|
||||
/** @var AggregateExpression */
|
||||
private $aggregateExpression;
|
||||
|
||||
public function getSql(SqlWalker $sqlWalker): string
|
||||
{
|
||||
return $this->aggregateExpression->dispatch($sqlWalker);
|
||||
}
|
||||
|
||||
public function parse(Parser $parser): void
|
||||
{
|
||||
$this->aggregateExpression = $parser->AggregateExpression();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\AggregateExpression;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "MIN" "(" ["DISTINCT"] StringPrimary ")"
|
||||
*/
|
||||
final class MinFunction extends FunctionNode
|
||||
{
|
||||
/** @var AggregateExpression */
|
||||
private $aggregateExpression;
|
||||
|
||||
public function getSql(SqlWalker $sqlWalker): string
|
||||
{
|
||||
return $this->aggregateExpression->dispatch($sqlWalker);
|
||||
}
|
||||
|
||||
public function parse(Parser $parser): void
|
||||
{
|
||||
$this->aggregateExpression = $parser->AggregateExpression();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\SimpleArithmeticExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class ModFunction extends FunctionNode
|
||||
{
|
||||
/** @var SimpleArithmeticExpression */
|
||||
public $firstSimpleArithmeticExpression;
|
||||
|
||||
/** @var SimpleArithmeticExpression */
|
||||
public $secondSimpleArithmeticExpression;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getModExpression(
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->firstSimpleArithmeticExpression),
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->secondSimpleArithmeticExpression)
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
|
||||
$this->secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\AST\PathExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
use function assert;
|
||||
|
||||
/**
|
||||
* "SIZE" "(" CollectionValuedPathExpression ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SizeFunction extends FunctionNode
|
||||
{
|
||||
/** @var PathExpression */
|
||||
public $collectionPathExpression;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @todo If the collection being counted is already joined, the SQL can be simpler (more efficient).
|
||||
*/
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
assert($this->collectionPathExpression->field !== null);
|
||||
$entityManager = $sqlWalker->getEntityManager();
|
||||
$platform = $entityManager->getConnection()->getDatabasePlatform();
|
||||
$quoteStrategy = $entityManager->getConfiguration()->getQuoteStrategy();
|
||||
$dqlAlias = $this->collectionPathExpression->identificationVariable;
|
||||
$assocField = $this->collectionPathExpression->field;
|
||||
|
||||
$class = $sqlWalker->getMetadataForDqlAlias($dqlAlias);
|
||||
$assoc = $class->associationMappings[$assocField];
|
||||
$sql = 'SELECT COUNT(*) FROM ';
|
||||
|
||||
if ($assoc['type'] === ClassMetadata::ONE_TO_MANY) {
|
||||
$targetClass = $entityManager->getClassMetadata($assoc['targetEntity']);
|
||||
$targetTableAlias = $sqlWalker->getSQLTableAlias($targetClass->getTableName());
|
||||
$sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
$sql .= $quoteStrategy->getTableName($targetClass, $platform) . ' ' . $targetTableAlias . ' WHERE ';
|
||||
|
||||
$owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']];
|
||||
|
||||
$first = true;
|
||||
|
||||
foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) {
|
||||
if ($first) {
|
||||
$first = false;
|
||||
} else {
|
||||
$sql .= ' AND ';
|
||||
}
|
||||
|
||||
$sql .= $targetTableAlias . '.' . $sourceColumn
|
||||
. ' = '
|
||||
. $sourceTableAlias . '.' . $quoteStrategy->getColumnName($class->fieldNames[$targetColumn], $class, $platform);
|
||||
}
|
||||
} else { // many-to-many
|
||||
$targetClass = $entityManager->getClassMetadata($assoc['targetEntity']);
|
||||
|
||||
$owningAssoc = $assoc['isOwningSide'] ? $assoc : $targetClass->associationMappings[$assoc['mappedBy']];
|
||||
$joinTable = $owningAssoc['joinTable'];
|
||||
|
||||
// SQL table aliases
|
||||
$joinTableAlias = $sqlWalker->getSQLTableAlias($joinTable['name']);
|
||||
$sourceTableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias);
|
||||
|
||||
// join to target table
|
||||
$sql .= $quoteStrategy->getJoinTableName($owningAssoc, $targetClass, $platform) . ' ' . $joinTableAlias . ' WHERE ';
|
||||
|
||||
$joinColumns = $assoc['isOwningSide']
|
||||
? $joinTable['joinColumns']
|
||||
: $joinTable['inverseJoinColumns'];
|
||||
|
||||
$first = true;
|
||||
|
||||
foreach ($joinColumns as $joinColumn) {
|
||||
if ($first) {
|
||||
$first = false;
|
||||
} else {
|
||||
$sql .= ' AND ';
|
||||
}
|
||||
|
||||
$sourceColumnName = $quoteStrategy->getColumnName(
|
||||
$class->fieldNames[$joinColumn['referencedColumnName']],
|
||||
$class,
|
||||
$platform
|
||||
);
|
||||
|
||||
$sql .= $joinTableAlias . '.' . $joinColumn['name']
|
||||
. ' = '
|
||||
. $sourceTableAlias . '.' . $sourceColumnName;
|
||||
}
|
||||
}
|
||||
|
||||
return '(' . $sql . ')';
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->collectionPathExpression = $parser->CollectionValuedPathExpression();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\SimpleArithmeticExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* "SQRT" "(" SimpleArithmeticExpression ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SqrtFunction extends FunctionNode
|
||||
{
|
||||
/** @var SimpleArithmeticExpression */
|
||||
public $simpleArithmeticExpression;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return sprintf(
|
||||
'SQRT(%s)',
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->simpleArithmeticExpression)
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\AST\SimpleArithmeticExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SubstringFunction extends FunctionNode
|
||||
{
|
||||
/** @var Node */
|
||||
public $stringPrimary;
|
||||
|
||||
/** @var SimpleArithmeticExpression */
|
||||
public $firstSimpleArithmeticExpression;
|
||||
|
||||
/** @var SimpleArithmeticExpression|null */
|
||||
public $secondSimpleArithmeticExpression = null;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
$optionalSecondSimpleArithmeticExpression = null;
|
||||
if ($this->secondSimpleArithmeticExpression !== null) {
|
||||
$optionalSecondSimpleArithmeticExpression = $sqlWalker->walkSimpleArithmeticExpression($this->secondSimpleArithmeticExpression);
|
||||
}
|
||||
|
||||
return $sqlWalker->getConnection()->getDatabasePlatform()->getSubstringExpression(
|
||||
$sqlWalker->walkStringPrimary($this->stringPrimary),
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->firstSimpleArithmeticExpression),
|
||||
$optionalSecondSimpleArithmeticExpression
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->stringPrimary = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
|
||||
$this->firstSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
|
||||
$lexer = $parser->getLexer();
|
||||
if ($lexer->isNextToken(Lexer::T_COMMA)) {
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
|
||||
$this->secondSimpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
}
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\AggregateExpression;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* "SUM" "(" ["DISTINCT"] StringPrimary ")"
|
||||
*/
|
||||
final class SumFunction extends FunctionNode
|
||||
{
|
||||
/** @var AggregateExpression */
|
||||
private $aggregateExpression;
|
||||
|
||||
public function getSql(SqlWalker $sqlWalker): string
|
||||
{
|
||||
return $this->aggregateExpression->dispatch($sqlWalker);
|
||||
}
|
||||
|
||||
public function parse(Parser $parser): void
|
||||
{
|
||||
$this->aggregateExpression = $parser->AggregateExpression();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\DBAL\Platforms\TrimMode;
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
use function assert;
|
||||
use function strcasecmp;
|
||||
|
||||
/**
|
||||
* "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class TrimFunction extends FunctionNode
|
||||
{
|
||||
/** @var bool */
|
||||
public $leading;
|
||||
|
||||
/** @var bool */
|
||||
public $trailing;
|
||||
|
||||
/** @var bool */
|
||||
public $both;
|
||||
|
||||
/** @var string|false */
|
||||
public $trimChar = false;
|
||||
|
||||
/** @var Node */
|
||||
public $stringPrimary;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
$stringPrimary = $sqlWalker->walkStringPrimary($this->stringPrimary);
|
||||
$platform = $sqlWalker->getConnection()->getDatabasePlatform();
|
||||
$trimMode = $this->getTrimMode();
|
||||
|
||||
if ($this->trimChar !== false) {
|
||||
return $platform->getTrimExpression(
|
||||
$stringPrimary,
|
||||
$trimMode,
|
||||
$platform->quoteStringLiteral($this->trimChar)
|
||||
);
|
||||
}
|
||||
|
||||
return $platform->getTrimExpression($stringPrimary, $trimMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$lexer = $parser->getLexer();
|
||||
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->parseTrimMode($parser);
|
||||
|
||||
if ($lexer->isNextToken(Lexer::T_STRING)) {
|
||||
$parser->match(Lexer::T_STRING);
|
||||
|
||||
assert($lexer->token !== null);
|
||||
$this->trimChar = $lexer->token->value;
|
||||
}
|
||||
|
||||
if ($this->leading || $this->trailing || $this->both || $this->trimChar) {
|
||||
$parser->match(Lexer::T_FROM);
|
||||
}
|
||||
|
||||
$this->stringPrimary = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
|
||||
/** @psalm-return TrimMode::* */
|
||||
private function getTrimMode(): int
|
||||
{
|
||||
if ($this->leading) {
|
||||
return TrimMode::LEADING;
|
||||
}
|
||||
|
||||
if ($this->trailing) {
|
||||
return TrimMode::TRAILING;
|
||||
}
|
||||
|
||||
if ($this->both) {
|
||||
return TrimMode::BOTH;
|
||||
}
|
||||
|
||||
return TrimMode::UNSPECIFIED;
|
||||
}
|
||||
|
||||
private function parseTrimMode(Parser $parser): void
|
||||
{
|
||||
$lexer = $parser->getLexer();
|
||||
assert($lexer->lookahead !== null);
|
||||
$value = $lexer->lookahead->value;
|
||||
|
||||
if (strcasecmp('leading', $value) === 0) {
|
||||
$parser->match(Lexer::T_LEADING);
|
||||
|
||||
$this->leading = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcasecmp('trailing', $value) === 0) {
|
||||
$parser->match(Lexer::T_TRAILING);
|
||||
|
||||
$this->trailing = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcasecmp('both', $value) === 0) {
|
||||
$parser->match(Lexer::T_BOTH);
|
||||
|
||||
$this->both = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* "UPPER" "(" StringPrimary ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class UpperFunction extends FunctionNode
|
||||
{
|
||||
/** @var Node */
|
||||
public $stringPrimary;
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return sprintf(
|
||||
'UPPER(%s)',
|
||||
$sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary)
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->stringPrimary = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class GeneralCaseExpression extends Node
|
||||
{
|
||||
/** @var mixed[] */
|
||||
public $whenClauses = [];
|
||||
|
||||
/** @var mixed */
|
||||
public $elseScalarExpression = null;
|
||||
|
||||
/**
|
||||
* @param mixed[] $whenClauses
|
||||
* @param mixed $elseScalarExpression
|
||||
*/
|
||||
public function __construct(array $whenClauses, $elseScalarExpression)
|
||||
{
|
||||
$this->whenClauses = $whenClauses;
|
||||
$this->elseScalarExpression = $elseScalarExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkGeneralCaseExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
class GroupByClause extends Node
|
||||
{
|
||||
/** @var mixed[] */
|
||||
public $groupByItems = [];
|
||||
|
||||
/** @param mixed[] $groupByItems */
|
||||
public function __construct(array $groupByItems)
|
||||
{
|
||||
$this->groupByItems = $groupByItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkGroupByClause($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
class HavingClause extends Node
|
||||
{
|
||||
/** @var ConditionalExpression|Phase2OptimizableConditional */
|
||||
public $conditionalExpression;
|
||||
|
||||
/** @param ConditionalExpression|Phase2OptimizableConditional $conditionalExpression */
|
||||
public function __construct($conditionalExpression)
|
||||
{
|
||||
$this->conditionalExpression = $conditionalExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkHavingClause($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class IdentificationVariableDeclaration extends Node
|
||||
{
|
||||
/** @var RangeVariableDeclaration|null */
|
||||
public $rangeVariableDeclaration = null;
|
||||
|
||||
/** @var IndexBy|null */
|
||||
public $indexBy = null;
|
||||
|
||||
/** @var mixed[] */
|
||||
public $joins = [];
|
||||
|
||||
/**
|
||||
* @param RangeVariableDeclaration|null $rangeVariableDecl
|
||||
* @param IndexBy|null $indexBy
|
||||
* @param mixed[] $joins
|
||||
*/
|
||||
public function __construct($rangeVariableDecl, $indexBy, array $joins)
|
||||
{
|
||||
$this->rangeVariableDeclaration = $rangeVariableDecl;
|
||||
$this->indexBy = $indexBy;
|
||||
$this->joins = $joins;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkIdentificationVariableDeclaration($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
/**
|
||||
* InExpression ::= ArithmeticExpression ["NOT"] "IN" "(" (Literal {"," Literal}* | Subselect) ")"
|
||||
*
|
||||
* @deprecated Use {@see InListExpression} or {@see InSubselectExpression} instead.
|
||||
*/
|
||||
class InExpression extends Node
|
||||
{
|
||||
/** @var bool */
|
||||
public $not;
|
||||
|
||||
/** @var ArithmeticExpression */
|
||||
public $expression;
|
||||
|
||||
/** @var mixed[] */
|
||||
public $literals = [];
|
||||
|
||||
/** @var Subselect|null */
|
||||
public $subselect;
|
||||
|
||||
/** @param ArithmeticExpression $expression */
|
||||
public function __construct($expression)
|
||||
{
|
||||
if (! $this instanceof InListExpression && ! $this instanceof InSubselectExpression) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10267',
|
||||
'%s is deprecated, use %s or %s instead.',
|
||||
self::class,
|
||||
InListExpression::class,
|
||||
InSubselectExpression::class
|
||||
);
|
||||
}
|
||||
|
||||
$this->expression = $expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
// We still call the deprecated method in order to not break existing custom SQL walkers.
|
||||
return $sqlWalker->walkInExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
class InListExpression extends InExpression
|
||||
{
|
||||
/** @var non-empty-list<mixed> */
|
||||
public $literals;
|
||||
|
||||
/** @param non-empty-list<mixed> $literals */
|
||||
public function __construct(ArithmeticExpression $expression, array $literals, bool $not = false)
|
||||
{
|
||||
$this->literals = $literals;
|
||||
$this->not = $not;
|
||||
|
||||
parent::__construct($expression);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
class InSubselectExpression extends InExpression
|
||||
{
|
||||
/** @var Subselect */
|
||||
public $subselect;
|
||||
|
||||
public function __construct(ArithmeticExpression $expression, Subselect $subselect, bool $not = false)
|
||||
{
|
||||
$this->subselect = $subselect;
|
||||
$this->not = $not;
|
||||
|
||||
parent::__construct($expression);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* IndexBy ::= "INDEX" "BY" SingleValuedPathExpression
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class IndexBy extends Node
|
||||
{
|
||||
/** @var PathExpression */
|
||||
public $singleValuedPathExpression = null;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* @var PathExpression
|
||||
*/
|
||||
public $simpleStateFieldPathExpression = null;
|
||||
|
||||
public function __construct(PathExpression $singleValuedPathExpression)
|
||||
{
|
||||
$this->singleValuedPathExpression = $this->simpleStateFieldPathExpression = $singleValuedPathExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkIndexBy($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
|
||||
use function is_numeric;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
class InputParameter extends Node
|
||||
{
|
||||
/** @var bool */
|
||||
public $isNamed;
|
||||
|
||||
/** @var string */
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @throws QueryException
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
if (strlen($value) === 1) {
|
||||
throw QueryException::invalidParameterFormat($value);
|
||||
}
|
||||
|
||||
$param = substr($value, 1);
|
||||
$this->isNamed = ! is_numeric($param);
|
||||
$this->name = $param;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkInputParameter($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
use function func_num_args;
|
||||
|
||||
/**
|
||||
* InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")")
|
||||
* InstanceOfParameter ::= AbstractSchemaName | InputParameter
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class InstanceOfExpression extends Node
|
||||
{
|
||||
/** @var bool */
|
||||
public $not;
|
||||
|
||||
/** @var string */
|
||||
public $identificationVariable;
|
||||
|
||||
/** @var non-empty-list<InputParameter|string> */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* @param string $identVariable
|
||||
* @param non-empty-list<InputParameter|string> $value
|
||||
*/
|
||||
public function __construct($identVariable, array $value = [], bool $not = false)
|
||||
{
|
||||
if (func_num_args() < 2) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10267',
|
||||
'Not passing a value for $value to %s() is deprecated.',
|
||||
__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->identificationVariable = $identVariable;
|
||||
$this->value = $value;
|
||||
$this->not = $not;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkInstanceOfExpression($this);
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression
|
||||
* ["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression]
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class Join extends Node
|
||||
{
|
||||
public const JOIN_TYPE_LEFT = 1;
|
||||
public const JOIN_TYPE_LEFTOUTER = 2;
|
||||
public const JOIN_TYPE_INNER = 3;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @psalm-var self::JOIN_TYPE_*
|
||||
*/
|
||||
public $joinType = self::JOIN_TYPE_INNER;
|
||||
|
||||
/** @var Node|null */
|
||||
public $joinAssociationDeclaration = null;
|
||||
|
||||
/** @var ConditionalExpression|Phase2OptimizableConditional|null */
|
||||
public $conditionalExpression = null;
|
||||
|
||||
/**
|
||||
* @param int $joinType
|
||||
* @param Node $joinAssociationDeclaration
|
||||
* @psalm-param self::JOIN_TYPE_* $joinType
|
||||
*/
|
||||
public function __construct($joinType, $joinAssociationDeclaration)
|
||||
{
|
||||
$this->joinType = $joinType;
|
||||
$this->joinAssociationDeclaration = $joinAssociationDeclaration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkJoin($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class JoinAssociationDeclaration extends Node
|
||||
{
|
||||
/** @var JoinAssociationPathExpression */
|
||||
public $joinAssociationPathExpression;
|
||||
|
||||
/** @var string */
|
||||
public $aliasIdentificationVariable;
|
||||
|
||||
/** @var IndexBy|null */
|
||||
public $indexBy;
|
||||
|
||||
/**
|
||||
* @param JoinAssociationPathExpression $joinAssociationPathExpression
|
||||
* @param string $aliasIdentificationVariable
|
||||
* @param IndexBy|null $indexBy
|
||||
*/
|
||||
public function __construct($joinAssociationPathExpression, $aliasIdentificationVariable, $indexBy)
|
||||
{
|
||||
$this->joinAssociationPathExpression = $joinAssociationPathExpression;
|
||||
$this->aliasIdentificationVariable = $aliasIdentificationVariable;
|
||||
$this->indexBy = $indexBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkJoinAssociationDeclaration($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* JoinAssociationPathExpression ::= IdentificationVariable "." (SingleValuedAssociationField | CollectionValuedAssociationField)
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class JoinAssociationPathExpression extends Node
|
||||
{
|
||||
/** @var string */
|
||||
public $identificationVariable;
|
||||
|
||||
/** @var string */
|
||||
public $associationField;
|
||||
|
||||
/**
|
||||
* @param string $identificationVariable
|
||||
* @param string $associationField
|
||||
*/
|
||||
public function __construct($identificationVariable, $associationField)
|
||||
{
|
||||
$this->identificationVariable = $identificationVariable;
|
||||
$this->associationField = $associationField;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* JoinClassPathExpression ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class JoinClassPathExpression extends Node
|
||||
{
|
||||
/** @var mixed */
|
||||
public $abstractSchemaName;
|
||||
|
||||
/** @var mixed */
|
||||
public $aliasIdentificationVariable;
|
||||
|
||||
/**
|
||||
* @param mixed $abstractSchemaName
|
||||
* @param mixed $aliasIdentificationVar
|
||||
*/
|
||||
public function __construct($abstractSchemaName, $aliasIdentificationVar)
|
||||
{
|
||||
$this->abstractSchemaName = $abstractSchemaName;
|
||||
$this->aliasIdentificationVariable = $aliasIdentificationVar;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkJoinPathExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* JoinVariableDeclaration ::= Join [IndexBy]
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class JoinVariableDeclaration extends Node
|
||||
{
|
||||
/** @var Join */
|
||||
public $join;
|
||||
|
||||
/** @var IndexBy|null */
|
||||
public $indexBy;
|
||||
|
||||
/**
|
||||
* @param Join $join
|
||||
* @param IndexBy|null $indexBy
|
||||
*/
|
||||
public function __construct($join, $indexBy)
|
||||
{
|
||||
$this->join = $join;
|
||||
$this->indexBy = $indexBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkJoinVariableDeclaration($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
|
||||
/**
|
||||
* LikeExpression ::= StringExpression ["NOT"] "LIKE" string ["ESCAPE" char]
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class LikeExpression extends Node
|
||||
{
|
||||
/** @var bool */
|
||||
public $not = false;
|
||||
|
||||
/** @var Node|string */
|
||||
public $stringExpression;
|
||||
|
||||
/** @var InputParameter|FunctionNode|PathExpression|Literal */
|
||||
public $stringPattern;
|
||||
|
||||
/** @var Literal|null */
|
||||
public $escapeChar;
|
||||
|
||||
/**
|
||||
* @param Node|string $stringExpression
|
||||
* @param InputParameter|FunctionNode|PathExpression|Literal $stringPattern
|
||||
* @param Literal|null $escapeChar
|
||||
*/
|
||||
public function __construct($stringExpression, $stringPattern, $escapeChar = null, bool $not = false)
|
||||
{
|
||||
$this->stringExpression = $stringExpression;
|
||||
$this->stringPattern = $stringPattern;
|
||||
$this->escapeChar = $escapeChar;
|
||||
$this->not = $not;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkLikeExpression($this);
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
class Literal extends Node
|
||||
{
|
||||
public const STRING = 1;
|
||||
public const BOOLEAN = 2;
|
||||
public const NUMERIC = 3;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @psalm-var self::*
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/** @var mixed */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* @param int $type
|
||||
* @param mixed $value
|
||||
* @psalm-param self::* $type
|
||||
*/
|
||||
public function __construct($type, $value)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkLiteral($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* NewObjectExpression ::= "NEW" IdentificationVariable "(" NewObjectArg {"," NewObjectArg}* ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class NewObjectExpression extends Node
|
||||
{
|
||||
/** @var string */
|
||||
public $className;
|
||||
|
||||
/** @var mixed[] */
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param mixed[] $args
|
||||
*/
|
||||
public function __construct($className, array $args)
|
||||
{
|
||||
$this->className = $className;
|
||||
$this->args = $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkNewObject($this);
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
use function get_debug_type;
|
||||
use function get_object_vars;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function str_repeat;
|
||||
use function var_export;
|
||||
|
||||
use const PHP_EOL;
|
||||
|
||||
/**
|
||||
* Abstract class of an AST node.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
abstract class Node
|
||||
{
|
||||
/**
|
||||
* Double-dispatch method, supposed to dispatch back to the walker.
|
||||
*
|
||||
* Implementation is not mandatory for all nodes.
|
||||
*
|
||||
* @param SqlWalker $walker
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws ASTException
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
throw ASTException::noDispatchForNode($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the AST Node into a string representation for information purpose only.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->dump($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function dump($value)
|
||||
{
|
||||
static $ident = 0;
|
||||
|
||||
$str = '';
|
||||
|
||||
if ($value instanceof Node) {
|
||||
$str .= get_debug_type($value) . '(' . PHP_EOL;
|
||||
$props = get_object_vars($value);
|
||||
|
||||
foreach ($props as $name => $prop) {
|
||||
$ident += 4;
|
||||
$str .= str_repeat(' ', $ident) . '"' . $name . '": '
|
||||
. $this->dump($prop) . ',' . PHP_EOL;
|
||||
$ident -= 4;
|
||||
}
|
||||
|
||||
$str .= str_repeat(' ', $ident) . ')';
|
||||
} elseif (is_array($value)) {
|
||||
$ident += 4;
|
||||
$str .= 'array(';
|
||||
$some = false;
|
||||
|
||||
foreach ($value as $k => $v) {
|
||||
$str .= PHP_EOL . str_repeat(' ', $ident) . '"'
|
||||
. $k . '" => ' . $this->dump($v) . ',';
|
||||
$some = true;
|
||||
}
|
||||
|
||||
$ident -= 4;
|
||||
$str .= ($some ? PHP_EOL . str_repeat(' ', $ident) : '') . ')';
|
||||
} elseif (is_object($value)) {
|
||||
$str .= 'instanceof(' . get_debug_type($value) . ')';
|
||||
} else {
|
||||
$str .= var_export($value, true);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class NullComparisonExpression extends Node
|
||||
{
|
||||
/** @var bool */
|
||||
public $not;
|
||||
|
||||
/** @var Node */
|
||||
public $expression;
|
||||
|
||||
/** @param Node $expression */
|
||||
public function __construct($expression, bool $not = false)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
$this->not = $not;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkNullComparisonExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* NullIfExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class NullIfExpression extends Node
|
||||
{
|
||||
/** @var mixed */
|
||||
public $firstExpression;
|
||||
|
||||
/** @var mixed */
|
||||
public $secondExpression;
|
||||
|
||||
/**
|
||||
* @param mixed $firstExpression
|
||||
* @param mixed $secondExpression
|
||||
*/
|
||||
public function __construct($firstExpression, $secondExpression)
|
||||
{
|
||||
$this->firstExpression = $firstExpression;
|
||||
$this->secondExpression = $secondExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkNullIfExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class OrderByClause extends Node
|
||||
{
|
||||
/** @var OrderByItem[] */
|
||||
public $orderByItems = [];
|
||||
|
||||
/** @param OrderByItem[] $orderByItems */
|
||||
public function __construct(array $orderByItems)
|
||||
{
|
||||
$this->orderByItems = $orderByItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkOrderByClause($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
use function strtoupper;
|
||||
|
||||
/**
|
||||
* OrderByItem ::= (ResultVariable | StateFieldPathExpression) ["ASC" | "DESC"]
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class OrderByItem extends Node
|
||||
{
|
||||
/** @var mixed */
|
||||
public $expression;
|
||||
|
||||
/** @var string */
|
||||
public $type;
|
||||
|
||||
/** @param mixed $expression */
|
||||
public function __construct($expression)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function isAsc()
|
||||
{
|
||||
return strtoupper($this->type) === 'ASC';
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function isDesc()
|
||||
{
|
||||
return strtoupper($this->type) === 'DESC';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkOrderByItem($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ParenthesisExpression ::= "(" ArithmeticPrimary ")"
|
||||
*/
|
||||
class ParenthesisExpression extends Node
|
||||
{
|
||||
/** @var Node */
|
||||
public $expression;
|
||||
|
||||
public function __construct(Node $expression)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkParenthesisExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
class PartialObjectExpression extends Node
|
||||
{
|
||||
/** @var string */
|
||||
public $identificationVariable;
|
||||
|
||||
/** @var mixed[] */
|
||||
public $partialFieldSet;
|
||||
|
||||
/**
|
||||
* @param string $identificationVariable
|
||||
* @param mixed[] $partialFieldSet
|
||||
*/
|
||||
public function __construct($identificationVariable, array $partialFieldSet)
|
||||
{
|
||||
$this->identificationVariable = $identificationVariable;
|
||||
$this->partialFieldSet = $partialFieldSet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
|
||||
* SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
|
||||
* StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression
|
||||
* SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
|
||||
* CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
|
||||
* StateField ::= {EmbeddedClassStateField "."}* SimpleStateField
|
||||
* SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField
|
||||
*/
|
||||
class PathExpression extends Node
|
||||
{
|
||||
public const TYPE_COLLECTION_VALUED_ASSOCIATION = 2;
|
||||
public const TYPE_SINGLE_VALUED_ASSOCIATION = 4;
|
||||
public const TYPE_STATE_FIELD = 8;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
* @psalm-var self::TYPE_*|null
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @psalm-var int-mask-of<self::TYPE_*>
|
||||
*/
|
||||
public $expectedType;
|
||||
|
||||
/** @var string */
|
||||
public $identificationVariable;
|
||||
|
||||
/** @var string|null */
|
||||
public $field;
|
||||
|
||||
/**
|
||||
* @param int $expectedType
|
||||
* @param string $identificationVariable
|
||||
* @param string|null $field
|
||||
* @psalm-param int-mask-of<self::TYPE_*> $expectedType
|
||||
*/
|
||||
public function __construct($expectedType, $identificationVariable, $field = null)
|
||||
{
|
||||
$this->expectedType = $expectedType;
|
||||
$this->identificationVariable = $identificationVariable;
|
||||
$this->field = $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkPathExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* Marks types that can be used in place of a ConditionalExpression as a phase
|
||||
* 2 optimization.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @psalm-inheritors ConditionalPrimary|ConditionalFactor|ConditionalTerm
|
||||
*/
|
||||
interface Phase2OptimizableConditional
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
use function strtoupper;
|
||||
|
||||
/**
|
||||
* QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class QuantifiedExpression extends Node
|
||||
{
|
||||
/** @var string */
|
||||
public $type;
|
||||
|
||||
/** @var Subselect */
|
||||
public $subselect;
|
||||
|
||||
/** @param Subselect $subselect */
|
||||
public function __construct($subselect)
|
||||
{
|
||||
$this->subselect = $subselect;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function isAll()
|
||||
{
|
||||
return strtoupper($this->type) === 'ALL';
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function isAny()
|
||||
{
|
||||
return strtoupper($this->type) === 'ANY';
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function isSome()
|
||||
{
|
||||
return strtoupper($this->type) === 'SOME';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkQuantifiedExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class RangeVariableDeclaration extends Node
|
||||
{
|
||||
/** @var string */
|
||||
public $abstractSchemaName;
|
||||
|
||||
/** @var string */
|
||||
public $aliasIdentificationVariable;
|
||||
|
||||
/** @var bool */
|
||||
public $isRoot;
|
||||
|
||||
/**
|
||||
* @param string $abstractSchemaName
|
||||
* @param string $aliasIdentificationVar
|
||||
* @param bool $isRoot
|
||||
*/
|
||||
public function __construct($abstractSchemaName, $aliasIdentificationVar, $isRoot = true)
|
||||
{
|
||||
$this->abstractSchemaName = $abstractSchemaName;
|
||||
$this->aliasIdentificationVariable = $aliasIdentificationVar;
|
||||
$this->isRoot = $isRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($walker)
|
||||
{
|
||||
return $walker->walkRangeVariableDeclaration($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SelectClause = "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SelectClause extends Node
|
||||
{
|
||||
/** @var bool */
|
||||
public $isDistinct;
|
||||
|
||||
/** @var mixed[] */
|
||||
public $selectExpressions = [];
|
||||
|
||||
/**
|
||||
* @param mixed[] $selectExpressions
|
||||
* @param bool $isDistinct
|
||||
*/
|
||||
public function __construct(array $selectExpressions, $isDistinct)
|
||||
{
|
||||
$this->isDistinct = $isDistinct;
|
||||
$this->selectExpressions = $selectExpressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkSelectClause($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SelectExpression ::= IdentificationVariable ["." "*"] | StateFieldPathExpression |
|
||||
* (AggregateExpression | "(" Subselect ")") [["AS"] ["HIDDEN"] FieldAliasIdentificationVariable]
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SelectExpression extends Node
|
||||
{
|
||||
/** @var mixed */
|
||||
public $expression;
|
||||
|
||||
/** @var string|null */
|
||||
public $fieldIdentificationVariable;
|
||||
|
||||
/** @var bool */
|
||||
public $hiddenAliasResultVariable;
|
||||
|
||||
/**
|
||||
* @param mixed $expression
|
||||
* @param string|null $fieldIdentificationVariable
|
||||
* @param bool $hiddenAliasResultVariable
|
||||
*/
|
||||
public function __construct($expression, $fieldIdentificationVariable, $hiddenAliasResultVariable = false)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
$this->fieldIdentificationVariable = $fieldIdentificationVariable;
|
||||
$this->hiddenAliasResultVariable = $hiddenAliasResultVariable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkSelectExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SelectStatement = SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SelectStatement extends Node
|
||||
{
|
||||
/** @var SelectClause */
|
||||
public $selectClause;
|
||||
|
||||
/** @var FromClause */
|
||||
public $fromClause;
|
||||
|
||||
/** @var WhereClause|null */
|
||||
public $whereClause;
|
||||
|
||||
/** @var GroupByClause|null */
|
||||
public $groupByClause;
|
||||
|
||||
/** @var HavingClause|null */
|
||||
public $havingClause;
|
||||
|
||||
/** @var OrderByClause|null */
|
||||
public $orderByClause;
|
||||
|
||||
/**
|
||||
* @param SelectClause $selectClause
|
||||
* @param FromClause $fromClause
|
||||
*/
|
||||
public function __construct($selectClause, $fromClause)
|
||||
{
|
||||
$this->selectClause = $selectClause;
|
||||
$this->fromClause = $fromClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkSelectStatement($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SimpleArithmeticExpression extends Node
|
||||
{
|
||||
/** @var mixed[] */
|
||||
public $arithmeticTerms = [];
|
||||
|
||||
/** @param mixed[] $arithmeticTerms */
|
||||
public function __construct(array $arithmeticTerms)
|
||||
{
|
||||
$this->arithmeticTerms = $arithmeticTerms;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkSimpleArithmeticExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SimpleCaseExpression extends Node
|
||||
{
|
||||
/** @var PathExpression */
|
||||
public $caseOperand = null;
|
||||
|
||||
/** @var mixed[] */
|
||||
public $simpleWhenClauses = [];
|
||||
|
||||
/** @var mixed */
|
||||
public $elseScalarExpression = null;
|
||||
|
||||
/**
|
||||
* @param PathExpression $caseOperand
|
||||
* @param mixed[] $simpleWhenClauses
|
||||
* @param mixed $elseScalarExpression
|
||||
*/
|
||||
public function __construct($caseOperand, array $simpleWhenClauses, $elseScalarExpression)
|
||||
{
|
||||
$this->caseOperand = $caseOperand;
|
||||
$this->simpleWhenClauses = $simpleWhenClauses;
|
||||
$this->elseScalarExpression = $elseScalarExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkSimpleCaseExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SimpleSelectClause extends Node
|
||||
{
|
||||
/** @var bool */
|
||||
public $isDistinct = false;
|
||||
|
||||
/** @var SimpleSelectExpression */
|
||||
public $simpleSelectExpression;
|
||||
|
||||
/**
|
||||
* @param SimpleSelectExpression $simpleSelectExpression
|
||||
* @param bool $isDistinct
|
||||
*/
|
||||
public function __construct($simpleSelectExpression, $isDistinct)
|
||||
{
|
||||
$this->simpleSelectExpression = $simpleSelectExpression;
|
||||
$this->isDistinct = $isDistinct;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkSimpleSelectClause($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SimpleSelectExpression ::= StateFieldPathExpression | IdentificationVariable
|
||||
* | (AggregateExpression [["AS"] FieldAliasIdentificationVariable])
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SimpleSelectExpression extends Node
|
||||
{
|
||||
/** @var Node|string */
|
||||
public $expression;
|
||||
|
||||
/** @var string */
|
||||
public $fieldIdentificationVariable;
|
||||
|
||||
/** @param Node|string $expression */
|
||||
public function __construct($expression)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkSimpleSelectExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SimpleWhenClause extends Node
|
||||
{
|
||||
/** @var mixed */
|
||||
public $caseScalarExpression = null;
|
||||
|
||||
/** @var mixed */
|
||||
public $thenScalarExpression = null;
|
||||
|
||||
/**
|
||||
* @param mixed $caseScalarExpression
|
||||
* @param mixed $thenScalarExpression
|
||||
*/
|
||||
public function __construct($caseScalarExpression, $thenScalarExpression)
|
||||
{
|
||||
$this->caseScalarExpression = $caseScalarExpression;
|
||||
$this->thenScalarExpression = $thenScalarExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkWhenClauseExpression($this);
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class Subselect extends Node
|
||||
{
|
||||
/** @var SimpleSelectClause */
|
||||
public $simpleSelectClause;
|
||||
|
||||
/** @var SubselectFromClause */
|
||||
public $subselectFromClause;
|
||||
|
||||
/** @var WhereClause|null */
|
||||
public $whereClause;
|
||||
|
||||
/** @var GroupByClause|null */
|
||||
public $groupByClause;
|
||||
|
||||
/** @var HavingClause|null */
|
||||
public $havingClause;
|
||||
|
||||
/** @var OrderByClause|null */
|
||||
public $orderByClause;
|
||||
|
||||
/**
|
||||
* @param SimpleSelectClause $simpleSelectClause
|
||||
* @param SubselectFromClause $subselectFromClause
|
||||
*/
|
||||
public function __construct($simpleSelectClause, $subselectFromClause)
|
||||
{
|
||||
$this->simpleSelectClause = $simpleSelectClause;
|
||||
$this->subselectFromClause = $subselectFromClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkSubselect($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SubselectFromClause extends Node
|
||||
{
|
||||
/** @var mixed[] */
|
||||
public $identificationVariableDeclarations = [];
|
||||
|
||||
/** @param mixed[] $identificationVariableDeclarations */
|
||||
public function __construct(array $identificationVariableDeclarations)
|
||||
{
|
||||
$this->identificationVariableDeclarations = $identificationVariableDeclarations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkSubselectFromClause($this);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SubselectIdentificationVariableDeclaration ::= AssociationPathExpression ["AS"] AliasIdentificationVariable
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SubselectIdentificationVariableDeclaration
|
||||
{
|
||||
/** @var PathExpression */
|
||||
public $associationPathExpression;
|
||||
|
||||
/** @var string */
|
||||
public $aliasIdentificationVariable;
|
||||
|
||||
/**
|
||||
* @param PathExpression $associationPathExpression
|
||||
* @param string $aliasIdentificationVariable
|
||||
*/
|
||||
public function __construct($associationPathExpression, $aliasIdentificationVariable)
|
||||
{
|
||||
$this->associationPathExpression = $associationPathExpression;
|
||||
$this->aliasIdentificationVariable = $aliasIdentificationVariable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
/**
|
||||
* Provides an API for resolving the type of a Node
|
||||
*/
|
||||
interface TypedExpression
|
||||
{
|
||||
public function getReturnType(): Type;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* UpdateClause ::= "UPDATE" AbstractSchemaName [["AS"] AliasIdentificationVariable] "SET" UpdateItem {"," UpdateItem}*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class UpdateClause extends Node
|
||||
{
|
||||
/** @var string */
|
||||
public $abstractSchemaName;
|
||||
|
||||
/** @var string */
|
||||
public $aliasIdentificationVariable;
|
||||
|
||||
/** @var mixed[] */
|
||||
public $updateItems = [];
|
||||
|
||||
/**
|
||||
* @param string $abstractSchemaName
|
||||
* @param mixed[] $updateItems
|
||||
*/
|
||||
public function __construct($abstractSchemaName, array $updateItems)
|
||||
{
|
||||
$this->abstractSchemaName = $abstractSchemaName;
|
||||
$this->updateItems = $updateItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkUpdateClause($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* UpdateItem ::= [IdentificationVariable "."] {StateField | SingleValuedAssociationField} "=" NewValue
|
||||
* NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary |
|
||||
* EnumPrimary | SimpleEntityExpression | "NULL"
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class UpdateItem extends Node
|
||||
{
|
||||
/** @var PathExpression */
|
||||
public $pathExpression;
|
||||
|
||||
/** @var InputParameter|ArithmeticExpression|null */
|
||||
public $newValue;
|
||||
|
||||
/**
|
||||
* @param PathExpression $pathExpression
|
||||
* @param InputParameter|ArithmeticExpression|null $newValue
|
||||
*/
|
||||
public function __construct($pathExpression, $newValue)
|
||||
{
|
||||
$this->pathExpression = $pathExpression;
|
||||
$this->newValue = $newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkUpdateItem($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* UpdateStatement = UpdateClause [WhereClause]
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class UpdateStatement extends Node
|
||||
{
|
||||
/** @var UpdateClause */
|
||||
public $updateClause;
|
||||
|
||||
/** @var WhereClause|null */
|
||||
public $whereClause;
|
||||
|
||||
/** @param UpdateClause $updateClause */
|
||||
public function __construct($updateClause)
|
||||
{
|
||||
$this->updateClause = $updateClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkUpdateStatement($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class WhenClause extends Node
|
||||
{
|
||||
/** @var ConditionalExpression|Phase2OptimizableConditional */
|
||||
public $caseConditionExpression;
|
||||
|
||||
/** @var mixed */
|
||||
public $thenScalarExpression = null;
|
||||
|
||||
/**
|
||||
* @param ConditionalExpression|Phase2OptimizableConditional $caseConditionExpression
|
||||
* @param mixed $thenScalarExpression
|
||||
*/
|
||||
public function __construct($caseConditionExpression, $thenScalarExpression)
|
||||
{
|
||||
$this->caseConditionExpression = $caseConditionExpression;
|
||||
$this->thenScalarExpression = $thenScalarExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkWhenClauseExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* WhereClause ::= "WHERE" ConditionalExpression
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class WhereClause extends Node
|
||||
{
|
||||
/** @var ConditionalExpression|Phase2OptimizableConditional */
|
||||
public $conditionalExpression;
|
||||
|
||||
/** @param ConditionalExpression|Phase2OptimizableConditional $conditionalExpression */
|
||||
public function __construct($conditionalExpression)
|
||||
{
|
||||
$this->conditionalExpression = $conditionalExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkWhereClause($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Result;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
use function array_diff;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function array_values;
|
||||
use function str_replace;
|
||||
|
||||
/**
|
||||
* Base class for SQL statement executors.
|
||||
*
|
||||
* @link http://www.doctrine-project.org
|
||||
*
|
||||
* @todo Rename: AbstractSQLExecutor
|
||||
*/
|
||||
abstract class AbstractSqlExecutor
|
||||
{
|
||||
/**
|
||||
* @deprecated use $sqlStatements instead
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
protected $_sqlStatements;
|
||||
|
||||
/** @var list<string>|string */
|
||||
protected $sqlStatements;
|
||||
|
||||
/** @var QueryCacheProfile */
|
||||
protected $queryCacheProfile;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->_sqlStatements = &$this->sqlStatements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL statements that are executed by the executor.
|
||||
*
|
||||
* @return list<string>|string All the SQL update statements.
|
||||
*/
|
||||
public function getSqlStatements()
|
||||
{
|
||||
return $this->sqlStatements;
|
||||
}
|
||||
|
||||
public function setQueryCacheProfile(QueryCacheProfile $qcp): void
|
||||
{
|
||||
$this->queryCacheProfile = $qcp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not use query cache
|
||||
*/
|
||||
public function removeQueryCacheProfile(): void
|
||||
{
|
||||
$this->queryCacheProfile = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all sql statements.
|
||||
*
|
||||
* @param Connection $conn The database connection that is used to execute the queries.
|
||||
* @param list<mixed>|array<string, mixed> $params The parameters.
|
||||
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types The parameter types.
|
||||
*
|
||||
* @return Result|int
|
||||
*/
|
||||
abstract public function execute(Connection $conn, array $params, array $types);
|
||||
|
||||
/** @return list<string> */
|
||||
public function __sleep(): array
|
||||
{
|
||||
/* Two reasons for this:
|
||||
- we do not need to serialize the deprecated property, we can
|
||||
rebuild the reference to the new property in __wakeup()
|
||||
- not having the legacy property in the serialized data means the
|
||||
serialized representation becomes compatible with 3.0.x, meaning
|
||||
there will not be a deprecation warning about a missing property
|
||||
when unserializing data */
|
||||
return array_values(array_diff(array_map(static function (string $prop): string {
|
||||
return str_replace("\0*\0", '', $prop);
|
||||
}, array_keys((array) $this)), ['_sqlStatements']));
|
||||
}
|
||||
|
||||
public function __wakeup(): void
|
||||
{
|
||||
if ($this->_sqlStatements !== null && $this->sqlStatements === null) {
|
||||
$this->sqlStatements = $this->_sqlStatements;
|
||||
}
|
||||
|
||||
$this->_sqlStatements = &$this->sqlStatements;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Query\AST;
|
||||
use Doctrine\ORM\Query\AST\DeleteStatement;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Utility\PersisterHelper;
|
||||
use Throwable;
|
||||
|
||||
use function array_merge;
|
||||
use function array_reverse;
|
||||
use function implode;
|
||||
|
||||
/**
|
||||
* Executes the SQL statements for bulk DQL DELETE statements on classes in
|
||||
* Class Table Inheritance (JOINED).
|
||||
*
|
||||
* @link http://www.doctrine-project.org
|
||||
*/
|
||||
class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
||||
{
|
||||
/** @var string */
|
||||
private $createTempTableSql;
|
||||
|
||||
/** @var string */
|
||||
private $dropTempTableSql;
|
||||
|
||||
/** @var string */
|
||||
private $insertSql;
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>MultiTableDeleteExecutor</tt>.
|
||||
*
|
||||
* Internal note: Any SQL construction and preparation takes place in the constructor for
|
||||
* best performance. With a query cache the executor will be cached.
|
||||
*
|
||||
* @param DeleteStatement $AST The root AST node of the DQL query.
|
||||
* @param SqlWalker $sqlWalker The walker used for SQL generation from the AST.
|
||||
*/
|
||||
public function __construct(AST\Node $AST, $sqlWalker)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$em = $sqlWalker->getEntityManager();
|
||||
$conn = $em->getConnection();
|
||||
$platform = $conn->getDatabasePlatform();
|
||||
$quoteStrategy = $em->getConfiguration()->getQuoteStrategy();
|
||||
|
||||
if ($conn instanceof PrimaryReadReplicaConnection) {
|
||||
$conn->ensureConnectedToPrimary();
|
||||
}
|
||||
|
||||
$primaryClass = $em->getClassMetadata($AST->deleteClause->abstractSchemaName);
|
||||
$primaryDqlAlias = $AST->deleteClause->aliasIdentificationVariable;
|
||||
$rootClass = $em->getClassMetadata($primaryClass->rootEntityName);
|
||||
|
||||
$tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName());
|
||||
$idColumnNames = $rootClass->getIdentifierColumnNames();
|
||||
$idColumnList = implode(', ', $idColumnNames);
|
||||
|
||||
// 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause()
|
||||
$sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $primaryDqlAlias);
|
||||
|
||||
$this->insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')'
|
||||
. ' SELECT t0.' . implode(', t0.', $idColumnNames);
|
||||
|
||||
$rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $primaryDqlAlias);
|
||||
$fromClause = new AST\FromClause([new AST\IdentificationVariableDeclaration($rangeDecl, null, [])]);
|
||||
$this->insertSql .= $sqlWalker->walkFromClause($fromClause);
|
||||
|
||||
// Append WHERE clause, if there is one.
|
||||
if ($AST->whereClause) {
|
||||
$this->insertSql .= $sqlWalker->walkWhereClause($AST->whereClause);
|
||||
}
|
||||
|
||||
// 2. Create ID subselect statement used in DELETE ... WHERE ... IN (subselect)
|
||||
$idSubselect = 'SELECT ' . $idColumnList . ' FROM ' . $tempTable;
|
||||
|
||||
// 3. Create and store DELETE statements
|
||||
$classNames = array_merge($primaryClass->parentClasses, [$primaryClass->name], $primaryClass->subClasses);
|
||||
foreach (array_reverse($classNames) as $className) {
|
||||
$tableName = $quoteStrategy->getTableName($em->getClassMetadata($className), $platform);
|
||||
$this->sqlStatements[] = 'DELETE FROM ' . $tableName
|
||||
. ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')';
|
||||
}
|
||||
|
||||
// 4. Store DDL for temporary identifier table.
|
||||
$columnDefinitions = [];
|
||||
foreach ($idColumnNames as $idColumnName) {
|
||||
$columnDefinitions[$idColumnName] = [
|
||||
'notnull' => true,
|
||||
'type' => Type::getType(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $em)),
|
||||
];
|
||||
}
|
||||
|
||||
$this->createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' ('
|
||||
. $platform->getColumnDeclarationListSQL($columnDefinitions) . ', PRIMARY KEY(' . implode(',', $idColumnNames) . '))';
|
||||
$this->dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function execute(Connection $conn, array $params, array $types)
|
||||
{
|
||||
// Create temporary id table
|
||||
$conn->executeStatement($this->createTempTableSql);
|
||||
|
||||
try {
|
||||
// Insert identifiers
|
||||
$numDeleted = $conn->executeStatement($this->insertSql, $params, $types);
|
||||
|
||||
// Execute DELETE statements
|
||||
foreach ($this->sqlStatements as $sql) {
|
||||
$conn->executeStatement($sql);
|
||||
}
|
||||
} catch (Throwable $exception) {
|
||||
// FAILURE! Drop temporary table to avoid possible collisions
|
||||
$conn->executeStatement($this->dropTempTableSql);
|
||||
|
||||
// Re-throw exception
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
// Drop temporary table
|
||||
$conn->executeStatement($this->dropTempTableSql);
|
||||
|
||||
return $numDeleted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Query\AST;
|
||||
use Doctrine\ORM\Query\AST\UpdateStatement;
|
||||
use Doctrine\ORM\Query\ParameterTypeInferer;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Utility\PersisterHelper;
|
||||
|
||||
use function array_merge;
|
||||
use function array_reverse;
|
||||
use function array_slice;
|
||||
use function implode;
|
||||
|
||||
/**
|
||||
* Executes the SQL statements for bulk DQL UPDATE statements on classes in
|
||||
* Class Table Inheritance (JOINED).
|
||||
*/
|
||||
class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
||||
{
|
||||
/** @var string */
|
||||
private $createTempTableSql;
|
||||
|
||||
/** @var string */
|
||||
private $dropTempTableSql;
|
||||
|
||||
/** @var string */
|
||||
private $insertSql;
|
||||
|
||||
/** @var mixed[] */
|
||||
private $sqlParameters = [];
|
||||
|
||||
/** @var int */
|
||||
private $numParametersInUpdateClause = 0;
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>MultiTableUpdateExecutor</tt>.
|
||||
*
|
||||
* Internal note: Any SQL construction and preparation takes place in the constructor for
|
||||
* best performance. With a query cache the executor will be cached.
|
||||
*
|
||||
* @param UpdateStatement $AST The root AST node of the DQL query.
|
||||
* @param SqlWalker $sqlWalker The walker used for SQL generation from the AST.
|
||||
*/
|
||||
public function __construct(AST\Node $AST, $sqlWalker)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$em = $sqlWalker->getEntityManager();
|
||||
$conn = $em->getConnection();
|
||||
$platform = $conn->getDatabasePlatform();
|
||||
$quoteStrategy = $em->getConfiguration()->getQuoteStrategy();
|
||||
|
||||
if ($conn instanceof PrimaryReadReplicaConnection) {
|
||||
$conn->ensureConnectedToPrimary();
|
||||
}
|
||||
|
||||
$updateClause = $AST->updateClause;
|
||||
$primaryClass = $sqlWalker->getEntityManager()->getClassMetadata($updateClause->abstractSchemaName);
|
||||
$rootClass = $em->getClassMetadata($primaryClass->rootEntityName);
|
||||
|
||||
$updateItems = $updateClause->updateItems;
|
||||
|
||||
$tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName());
|
||||
$idColumnNames = $rootClass->getIdentifierColumnNames();
|
||||
$idColumnList = implode(', ', $idColumnNames);
|
||||
|
||||
// 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause()
|
||||
$sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $updateClause->aliasIdentificationVariable);
|
||||
|
||||
$this->insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')'
|
||||
. ' SELECT t0.' . implode(', t0.', $idColumnNames);
|
||||
|
||||
$rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $updateClause->aliasIdentificationVariable);
|
||||
$fromClause = new AST\FromClause([new AST\IdentificationVariableDeclaration($rangeDecl, null, [])]);
|
||||
|
||||
$this->insertSql .= $sqlWalker->walkFromClause($fromClause);
|
||||
|
||||
// 2. Create ID subselect statement used in UPDATE ... WHERE ... IN (subselect)
|
||||
$idSubselect = 'SELECT ' . $idColumnList . ' FROM ' . $tempTable;
|
||||
|
||||
// 3. Create and store UPDATE statements
|
||||
$classNames = array_merge($primaryClass->parentClasses, [$primaryClass->name], $primaryClass->subClasses);
|
||||
|
||||
foreach (array_reverse($classNames) as $className) {
|
||||
$affected = false;
|
||||
$class = $em->getClassMetadata($className);
|
||||
$updateSql = 'UPDATE ' . $quoteStrategy->getTableName($class, $platform) . ' SET ';
|
||||
|
||||
$sqlParameters = [];
|
||||
foreach ($updateItems as $updateItem) {
|
||||
$field = $updateItem->pathExpression->field;
|
||||
|
||||
if (
|
||||
(isset($class->fieldMappings[$field]) && ! isset($class->fieldMappings[$field]['inherited'])) ||
|
||||
(isset($class->associationMappings[$field]) && ! isset($class->associationMappings[$field]['inherited']))
|
||||
) {
|
||||
$newValue = $updateItem->newValue;
|
||||
|
||||
if (! $affected) {
|
||||
$affected = true;
|
||||
} else {
|
||||
$updateSql .= ', ';
|
||||
}
|
||||
|
||||
$updateSql .= $sqlWalker->walkUpdateItem($updateItem);
|
||||
|
||||
if ($newValue instanceof AST\InputParameter) {
|
||||
$sqlParameters[] = $newValue->name;
|
||||
|
||||
++$this->numParametersInUpdateClause;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($affected) {
|
||||
$this->sqlParameters[] = $sqlParameters;
|
||||
$this->sqlStatements[] = $updateSql . ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')';
|
||||
}
|
||||
}
|
||||
|
||||
// Append WHERE clause to insertSql, if there is one.
|
||||
if ($AST->whereClause) {
|
||||
$this->insertSql .= $sqlWalker->walkWhereClause($AST->whereClause);
|
||||
}
|
||||
|
||||
// 4. Store DDL for temporary identifier table.
|
||||
$columnDefinitions = [];
|
||||
|
||||
foreach ($idColumnNames as $idColumnName) {
|
||||
$columnDefinitions[$idColumnName] = [
|
||||
'notnull' => true,
|
||||
'type' => Type::getType(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $em)),
|
||||
];
|
||||
}
|
||||
|
||||
$this->createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' ('
|
||||
. $platform->getColumnDeclarationListSQL($columnDefinitions) . ', PRIMARY KEY(' . implode(',', $idColumnNames) . '))';
|
||||
|
||||
$this->dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function execute(Connection $conn, array $params, array $types)
|
||||
{
|
||||
// Create temporary id table
|
||||
$conn->executeStatement($this->createTempTableSql);
|
||||
|
||||
try {
|
||||
// Insert identifiers. Parameters from the update clause are cut off.
|
||||
$numUpdated = $conn->executeStatement(
|
||||
$this->insertSql,
|
||||
array_slice($params, $this->numParametersInUpdateClause),
|
||||
array_slice($types, $this->numParametersInUpdateClause)
|
||||
);
|
||||
|
||||
// Execute UPDATE statements
|
||||
foreach ($this->sqlStatements as $key => $statement) {
|
||||
$paramValues = [];
|
||||
$paramTypes = [];
|
||||
|
||||
if (isset($this->sqlParameters[$key])) {
|
||||
foreach ($this->sqlParameters[$key] as $parameterKey => $parameterName) {
|
||||
$paramValues[] = $params[$parameterKey];
|
||||
$paramTypes[] = $types[$parameterKey] ?? ParameterTypeInferer::inferType($params[$parameterKey]);
|
||||
}
|
||||
}
|
||||
|
||||
$conn->executeStatement($statement, $paramValues, $paramTypes);
|
||||
}
|
||||
} finally {
|
||||
// Drop temporary table
|
||||
$conn->executeStatement($this->dropTempTableSql);
|
||||
}
|
||||
|
||||
return $numUpdated;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Result;
|
||||
use Doctrine\ORM\Query\AST\SelectStatement;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* Executor that executes the SQL statement for simple DQL SELECT statements.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class SingleSelectExecutor extends AbstractSqlExecutor
|
||||
{
|
||||
public function __construct(SelectStatement $AST, SqlWalker $sqlWalker)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->sqlStatements = $sqlWalker->walkSelectStatement($AST);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return Result
|
||||
*/
|
||||
public function execute(Connection $conn, array $params, array $types)
|
||||
{
|
||||
return $conn->executeQuery($this->sqlStatements, $params, $types, $this->queryCacheProfile);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
|
||||
use Doctrine\ORM\Query\AST;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* Executor that executes the SQL statements for DQL DELETE/UPDATE statements on classes
|
||||
* that are mapped to a single table.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor.
|
||||
*/
|
||||
class SingleTableDeleteUpdateExecutor extends AbstractSqlExecutor
|
||||
{
|
||||
/** @param SqlWalker $sqlWalker */
|
||||
public function __construct(AST\Node $AST, $sqlWalker)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if ($AST instanceof AST\UpdateStatement) {
|
||||
$this->sqlStatements = $sqlWalker->walkUpdateStatement($AST);
|
||||
} elseif ($AST instanceof AST\DeleteStatement) {
|
||||
$this->sqlStatements = $sqlWalker->walkDeleteStatement($AST);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function execute(Connection $conn, array $params, array $types)
|
||||
{
|
||||
if ($conn instanceof PrimaryReadReplicaConnection) {
|
||||
$conn->ensureConnectedToPrimary();
|
||||
}
|
||||
|
||||
return $conn->executeStatement($this->sqlStatements, $params, $types);
|
||||
}
|
||||
}
|
||||
+689
@@ -0,0 +1,689 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
use Traversable;
|
||||
|
||||
use function func_get_args;
|
||||
use function implode;
|
||||
use function is_bool;
|
||||
use function is_float;
|
||||
use function is_int;
|
||||
use function is_iterable;
|
||||
use function iterator_to_array;
|
||||
use function str_replace;
|
||||
|
||||
/**
|
||||
* This class is used to generate DQL expressions via a set of PHP static functions.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @todo Rename: ExpressionBuilder
|
||||
*/
|
||||
class Expr
|
||||
{
|
||||
/**
|
||||
* Creates a conjunction of the given boolean expressions.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* [php]
|
||||
* // (u.type = ?1) AND (u.role = ?2)
|
||||
* $expr->andX($expr->eq('u.type', ':1'), $expr->eq('u.role', ':2'));
|
||||
*
|
||||
* @param Expr\Comparison|Expr\Func|Expr\Andx|Expr\Orx|string $x Optional clause. Defaults to null,
|
||||
* but requires at least one defined
|
||||
* when converting to string.
|
||||
* @psalm-param Expr\Comparison|Expr\Func|Expr\Andx|Expr\Orx|string ...$x
|
||||
*
|
||||
* @return Expr\Andx
|
||||
*/
|
||||
public function andX($x = null)
|
||||
{
|
||||
return new Expr\Andx(func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a disjunction of the given boolean expressions.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* [php]
|
||||
* // (u.type = ?1) OR (u.role = ?2)
|
||||
* $q->where($q->expr()->orX('u.type = ?1', 'u.role = ?2'));
|
||||
*
|
||||
* @param Expr\Comparison|Expr\Func|Expr\Andx|Expr\Orx|string $x Optional clause. Defaults to null,
|
||||
* but requires at least one defined
|
||||
* when converting to string.
|
||||
* @psalm-param Expr\Comparison|Expr\Func|Expr\Andx|Expr\Orx|string ...$x
|
||||
*
|
||||
* @return Expr\Orx
|
||||
*/
|
||||
public function orX($x = null)
|
||||
{
|
||||
return new Expr\Orx(func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASCending order expression.
|
||||
*
|
||||
* @param mixed $expr
|
||||
*
|
||||
* @return Expr\OrderBy
|
||||
*/
|
||||
public function asc($expr)
|
||||
{
|
||||
return new Expr\OrderBy($expr, 'ASC');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DESCending order expression.
|
||||
*
|
||||
* @param mixed $expr
|
||||
*
|
||||
* @return Expr\OrderBy
|
||||
*/
|
||||
public function desc($expr)
|
||||
{
|
||||
return new Expr\OrderBy($expr, 'DESC');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an equality comparison expression with the given arguments.
|
||||
*
|
||||
* First argument is considered the left expression and the second is the right expression.
|
||||
* When converted to string, it will generated a <left expr> = <right expr>. Example:
|
||||
*
|
||||
* [php]
|
||||
* // u.id = ?1
|
||||
* $expr->eq('u.id', '?1');
|
||||
*
|
||||
* @param mixed $x Left expression.
|
||||
* @param mixed $y Right expression.
|
||||
*
|
||||
* @return Expr\Comparison
|
||||
*/
|
||||
public function eq($x, $y)
|
||||
{
|
||||
return new Expr\Comparison($x, Expr\Comparison::EQ, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of Expr\Comparison, with the given arguments.
|
||||
* First argument is considered the left expression and the second is the right expression.
|
||||
* When converted to string, it will generated a <left expr> <> <right expr>. Example:
|
||||
*
|
||||
* [php]
|
||||
* // u.id <> ?1
|
||||
* $q->where($q->expr()->neq('u.id', '?1'));
|
||||
*
|
||||
* @param mixed $x Left expression.
|
||||
* @param mixed $y Right expression.
|
||||
*
|
||||
* @return Expr\Comparison
|
||||
*/
|
||||
public function neq($x, $y)
|
||||
{
|
||||
return new Expr\Comparison($x, Expr\Comparison::NEQ, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of Expr\Comparison, with the given arguments.
|
||||
* First argument is considered the left expression and the second is the right expression.
|
||||
* When converted to string, it will generated a <left expr> < <right expr>. Example:
|
||||
*
|
||||
* [php]
|
||||
* // u.id < ?1
|
||||
* $q->where($q->expr()->lt('u.id', '?1'));
|
||||
*
|
||||
* @param mixed $x Left expression.
|
||||
* @param mixed $y Right expression.
|
||||
*
|
||||
* @return Expr\Comparison
|
||||
*/
|
||||
public function lt($x, $y)
|
||||
{
|
||||
return new Expr\Comparison($x, Expr\Comparison::LT, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of Expr\Comparison, with the given arguments.
|
||||
* First argument is considered the left expression and the second is the right expression.
|
||||
* When converted to string, it will generated a <left expr> <= <right expr>. Example:
|
||||
*
|
||||
* [php]
|
||||
* // u.id <= ?1
|
||||
* $q->where($q->expr()->lte('u.id', '?1'));
|
||||
*
|
||||
* @param mixed $x Left expression.
|
||||
* @param mixed $y Right expression.
|
||||
*
|
||||
* @return Expr\Comparison
|
||||
*/
|
||||
public function lte($x, $y)
|
||||
{
|
||||
return new Expr\Comparison($x, Expr\Comparison::LTE, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of Expr\Comparison, with the given arguments.
|
||||
* First argument is considered the left expression and the second is the right expression.
|
||||
* When converted to string, it will generated a <left expr> > <right expr>. Example:
|
||||
*
|
||||
* [php]
|
||||
* // u.id > ?1
|
||||
* $q->where($q->expr()->gt('u.id', '?1'));
|
||||
*
|
||||
* @param mixed $x Left expression.
|
||||
* @param mixed $y Right expression.
|
||||
*
|
||||
* @return Expr\Comparison
|
||||
*/
|
||||
public function gt($x, $y)
|
||||
{
|
||||
return new Expr\Comparison($x, Expr\Comparison::GT, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of Expr\Comparison, with the given arguments.
|
||||
* First argument is considered the left expression and the second is the right expression.
|
||||
* When converted to string, it will generated a <left expr> >= <right expr>. Example:
|
||||
*
|
||||
* [php]
|
||||
* // u.id >= ?1
|
||||
* $q->where($q->expr()->gte('u.id', '?1'));
|
||||
*
|
||||
* @param mixed $x Left expression.
|
||||
* @param mixed $y Right expression.
|
||||
*
|
||||
* @return Expr\Comparison
|
||||
*/
|
||||
public function gte($x, $y)
|
||||
{
|
||||
return new Expr\Comparison($x, Expr\Comparison::GTE, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of AVG() function, with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used in AVG() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function avg($x)
|
||||
{
|
||||
return new Expr\Func('AVG', [$x]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of MAX() function, with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used in MAX() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function max($x)
|
||||
{
|
||||
return new Expr\Func('MAX', [$x]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of MIN() function, with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used in MIN() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function min($x)
|
||||
{
|
||||
return new Expr\Func('MIN', [$x]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of COUNT() function, with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used in COUNT() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function count($x)
|
||||
{
|
||||
return new Expr\Func('COUNT', [$x]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of COUNT(DISTINCT) function, with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used in COUNT(DISTINCT) function.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function countDistinct($x)
|
||||
{
|
||||
return 'COUNT(DISTINCT ' . implode(', ', func_get_args()) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of EXISTS() function, with the given DQL Subquery.
|
||||
*
|
||||
* @param mixed $subquery DQL Subquery to be used in EXISTS() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function exists($subquery)
|
||||
{
|
||||
return new Expr\Func('EXISTS', [$subquery]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of ALL() function, with the given DQL Subquery.
|
||||
*
|
||||
* @param mixed $subquery DQL Subquery to be used in ALL() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function all($subquery)
|
||||
{
|
||||
return new Expr\Func('ALL', [$subquery]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SOME() function expression with the given DQL subquery.
|
||||
*
|
||||
* @param mixed $subquery DQL Subquery to be used in SOME() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function some($subquery)
|
||||
{
|
||||
return new Expr\Func('SOME', [$subquery]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ANY() function expression with the given DQL subquery.
|
||||
*
|
||||
* @param mixed $subquery DQL Subquery to be used in ANY() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function any($subquery)
|
||||
{
|
||||
return new Expr\Func('ANY', [$subquery]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a negation expression of the given restriction.
|
||||
*
|
||||
* @param mixed $restriction Restriction to be used in NOT() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function not($restriction)
|
||||
{
|
||||
return new Expr\Func('NOT', [$restriction]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ABS() function expression with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used in ABS() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function abs($x)
|
||||
{
|
||||
return new Expr\Func('ABS', [$x]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MOD($x, $y) function expression to return the remainder of $x divided by $y.
|
||||
*
|
||||
* @param mixed $x
|
||||
* @param mixed $y
|
||||
*/
|
||||
public function mod($x, $y): Expr\Func
|
||||
{
|
||||
return new Expr\Func('MOD', [$x, $y]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a product mathematical expression with the given arguments.
|
||||
*
|
||||
* First argument is considered the left expression and the second is the right expression.
|
||||
* When converted to string, it will generated a <left expr> * <right expr>. Example:
|
||||
*
|
||||
* [php]
|
||||
* // u.salary * u.percentAnnualSalaryIncrease
|
||||
* $q->expr()->prod('u.salary', 'u.percentAnnualSalaryIncrease')
|
||||
*
|
||||
* @param mixed $x Left expression.
|
||||
* @param mixed $y Right expression.
|
||||
*
|
||||
* @return Expr\Math
|
||||
*/
|
||||
public function prod($x, $y)
|
||||
{
|
||||
return new Expr\Math($x, '*', $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a difference mathematical expression with the given arguments.
|
||||
* First argument is considered the left expression and the second is the right expression.
|
||||
* When converted to string, it will generated a <left expr> - <right expr>. Example:
|
||||
*
|
||||
* [php]
|
||||
* // u.monthlySubscriptionCount - 1
|
||||
* $q->expr()->diff('u.monthlySubscriptionCount', '1')
|
||||
*
|
||||
* @param mixed $x Left expression.
|
||||
* @param mixed $y Right expression.
|
||||
*
|
||||
* @return Expr\Math
|
||||
*/
|
||||
public function diff($x, $y)
|
||||
{
|
||||
return new Expr\Math($x, '-', $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sum mathematical expression with the given arguments.
|
||||
* First argument is considered the left expression and the second is the right expression.
|
||||
* When converted to string, it will generated a <left expr> + <right expr>. Example:
|
||||
*
|
||||
* [php]
|
||||
* // u.numChildren + 1
|
||||
* $q->expr()->sum('u.numChildren', '1')
|
||||
*
|
||||
* @param mixed $x Left expression.
|
||||
* @param mixed $y Right expression.
|
||||
*
|
||||
* @return Expr\Math
|
||||
*/
|
||||
public function sum($x, $y)
|
||||
{
|
||||
return new Expr\Math($x, '+', $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a quotient mathematical expression with the given arguments.
|
||||
* First argument is considered the left expression and the second is the right expression.
|
||||
* When converted to string, it will generated a <left expr> / <right expr>. Example:
|
||||
*
|
||||
* [php]
|
||||
* // u.total / u.period
|
||||
* $expr->quot('u.total', 'u.period')
|
||||
*
|
||||
* @param mixed $x Left expression.
|
||||
* @param mixed $y Right expression.
|
||||
*
|
||||
* @return Expr\Math
|
||||
*/
|
||||
public function quot($x, $y)
|
||||
{
|
||||
return new Expr\Math($x, '/', $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SQRT() function expression with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used in SQRT() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function sqrt($x)
|
||||
{
|
||||
return new Expr\Func('SQRT', [$x]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IN() expression with the given arguments.
|
||||
*
|
||||
* @param string $x Field in string format to be restricted by IN() function.
|
||||
* @param mixed $y Argument to be used in IN() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function in($x, $y)
|
||||
{
|
||||
if (is_iterable($y)) {
|
||||
if ($y instanceof Traversable) {
|
||||
$y = iterator_to_array($y);
|
||||
}
|
||||
|
||||
foreach ($y as &$literal) {
|
||||
if (! ($literal instanceof Expr\Literal)) {
|
||||
$literal = $this->quoteLiteral($literal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Expr\Func($x . ' IN', (array) $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a NOT IN() expression with the given arguments.
|
||||
*
|
||||
* @param string $x Field in string format to be restricted by NOT IN() function.
|
||||
* @param mixed $y Argument to be used in NOT IN() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function notIn($x, $y)
|
||||
{
|
||||
if (is_iterable($y)) {
|
||||
if ($y instanceof Traversable) {
|
||||
$y = iterator_to_array($y);
|
||||
}
|
||||
|
||||
foreach ($y as &$literal) {
|
||||
if (! ($literal instanceof Expr\Literal)) {
|
||||
$literal = $this->quoteLiteral($literal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Expr\Func($x . ' NOT IN', (array) $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IS NULL expression with the given arguments.
|
||||
*
|
||||
* @param string $x Field in string format to be restricted by IS NULL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function isNull($x)
|
||||
{
|
||||
return $x . ' IS NULL';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IS NOT NULL expression with the given arguments.
|
||||
*
|
||||
* @param string $x Field in string format to be restricted by IS NOT NULL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function isNotNull($x)
|
||||
{
|
||||
return $x . ' IS NOT NULL';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a LIKE() comparison expression with the given arguments.
|
||||
*
|
||||
* @param string $x Field in string format to be inspected by LIKE() comparison.
|
||||
* @param mixed $y Argument to be used in LIKE() comparison.
|
||||
*
|
||||
* @return Expr\Comparison
|
||||
*/
|
||||
public function like($x, $y)
|
||||
{
|
||||
return new Expr\Comparison($x, 'LIKE', $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a NOT LIKE() comparison expression with the given arguments.
|
||||
*
|
||||
* @param string $x Field in string format to be inspected by LIKE() comparison.
|
||||
* @param mixed $y Argument to be used in LIKE() comparison.
|
||||
*
|
||||
* @return Expr\Comparison
|
||||
*/
|
||||
public function notLike($x, $y)
|
||||
{
|
||||
return new Expr\Comparison($x, 'NOT LIKE', $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CONCAT() function expression with the given arguments.
|
||||
*
|
||||
* @param mixed $x First argument to be used in CONCAT() function.
|
||||
* @param mixed $y,... Other arguments to be used in CONCAT() function.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function concat($x, $y)
|
||||
{
|
||||
return new Expr\Func('CONCAT', func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SUBSTRING() function expression with the given arguments.
|
||||
*
|
||||
* @param mixed $x Argument to be used as string to be cropped by SUBSTRING() function.
|
||||
* @param int $from Initial offset to start cropping string. May accept negative values.
|
||||
* @param int|null $len Length of crop. May accept negative values.
|
||||
*
|
||||
* @return Expr\Func
|
||||
*/
|
||||
public function substring($x, $from, $len = null)
|
||||
{
|
||||
$args = [$x, $from];
|
||||
if ($len !== null) {
|
||||
$args[] = $len;
|
||||
}
|
||||
|
||||
return new Expr\Func('SUBSTRING', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a LOWER() function expression with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used in LOWER() function.
|
||||
*
|
||||
* @return Expr\Func A LOWER function expression.
|
||||
*/
|
||||
public function lower($x)
|
||||
{
|
||||
return new Expr\Func('LOWER', [$x]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an UPPER() function expression with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used in UPPER() function.
|
||||
*
|
||||
* @return Expr\Func An UPPER function expression.
|
||||
*/
|
||||
public function upper($x)
|
||||
{
|
||||
return new Expr\Func('UPPER', [$x]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a LENGTH() function expression with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used as argument of LENGTH() function.
|
||||
*
|
||||
* @return Expr\Func A LENGTH function expression.
|
||||
*/
|
||||
public function length($x)
|
||||
{
|
||||
return new Expr\Func('LENGTH', [$x]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a literal expression of the given argument.
|
||||
*
|
||||
* @param scalar $literal Argument to be converted to literal.
|
||||
*
|
||||
* @return Expr\Literal
|
||||
*/
|
||||
public function literal($literal)
|
||||
{
|
||||
return new Expr\Literal($this->quoteLiteral($literal));
|
||||
}
|
||||
|
||||
/**
|
||||
* Quotes a literal value, if necessary, according to the DQL syntax.
|
||||
*
|
||||
* @param scalar $literal The literal value.
|
||||
*/
|
||||
private function quoteLiteral($literal): string
|
||||
{
|
||||
if (is_int($literal) || is_float($literal)) {
|
||||
return (string) $literal;
|
||||
}
|
||||
|
||||
if (is_bool($literal)) {
|
||||
return $literal ? 'true' : 'false';
|
||||
}
|
||||
|
||||
return "'" . str_replace("'", "''", $literal) . "'";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of BETWEEN() function, with the given argument.
|
||||
*
|
||||
* @param mixed $val Valued to be inspected by range values.
|
||||
* @param int|string $x Starting range value to be used in BETWEEN() function.
|
||||
* @param int|string $y End point value to be used in BETWEEN() function.
|
||||
*
|
||||
* @return string A BETWEEN expression.
|
||||
*/
|
||||
public function between($val, $x, $y)
|
||||
{
|
||||
return $val . ' BETWEEN ' . $x . ' AND ' . $y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of TRIM() function, with the given argument.
|
||||
*
|
||||
* @param mixed $x Argument to be used as argument of TRIM() function.
|
||||
*
|
||||
* @return Expr\Func a TRIM expression.
|
||||
*/
|
||||
public function trim($x)
|
||||
{
|
||||
return new Expr\Func('TRIM', $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of MEMBER OF function, with the given arguments.
|
||||
*
|
||||
* @param string $x Value to be checked
|
||||
* @param string $y Value to be checked against
|
||||
*
|
||||
* @return Expr\Comparison
|
||||
*/
|
||||
public function isMemberOf($x, $y)
|
||||
{
|
||||
return new Expr\Comparison($x, 'MEMBER OF', $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of INSTANCE OF function, with the given arguments.
|
||||
*
|
||||
* @param string $x Value to be checked
|
||||
* @param string $y Value to be checked against
|
||||
*
|
||||
* @return Expr\Comparison
|
||||
*/
|
||||
public function isInstanceOf($x, $y)
|
||||
{
|
||||
return new Expr\Comparison($x, 'INSTANCE OF', $y);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Expr;
|
||||
|
||||
/**
|
||||
* Expression class for building DQL and parts.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class Andx extends Composite
|
||||
{
|
||||
/** @var string */
|
||||
protected $separator = ' AND ';
|
||||
|
||||
/** @var string[] */
|
||||
protected $allowedClasses = [
|
||||
Comparison::class,
|
||||
Func::class,
|
||||
Orx::class,
|
||||
self::class,
|
||||
];
|
||||
|
||||
/** @psalm-var list<string|Comparison|Func|Orx|self> */
|
||||
protected $parts = [];
|
||||
|
||||
/** @psalm-return list<string|Comparison|Func|Orx|self> */
|
||||
public function getParts()
|
||||
{
|
||||
return $this->parts;
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Expr;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Stringable;
|
||||
|
||||
use function count;
|
||||
use function get_class;
|
||||
use function get_debug_type;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Abstract base Expr class for building DQL parts.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
abstract class Base
|
||||
{
|
||||
/** @var string */
|
||||
protected $preSeparator = '(';
|
||||
|
||||
/** @var string */
|
||||
protected $separator = ', ';
|
||||
|
||||
/** @var string */
|
||||
protected $postSeparator = ')';
|
||||
|
||||
/** @var list<class-string> */
|
||||
protected $allowedClasses = [];
|
||||
|
||||
/** @var list<string|Stringable> */
|
||||
protected $parts = [];
|
||||
|
||||
/** @param mixed $args */
|
||||
public function __construct($args = [])
|
||||
{
|
||||
$this->addMultiple($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[]|object[]|string|object $args
|
||||
* @psalm-param list<string|object>|string|object $args
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addMultiple($args = [])
|
||||
{
|
||||
foreach ((array) $args as $arg) {
|
||||
$this->add($arg);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $arg
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function add($arg)
|
||||
{
|
||||
if ($arg !== null && (! $arg instanceof self || $arg->count() > 0)) {
|
||||
// If we decide to keep Expr\Base instances, we can use this check
|
||||
if (! is_string($arg) && ! in_array(get_class($arg), $this->allowedClasses, true)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
"Expression of type '%s' not allowed in this context.",
|
||||
get_debug_type($arg)
|
||||
));
|
||||
}
|
||||
|
||||
$this->parts[] = $arg;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @psalm-return 0|positive-int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->parts);
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->count() === 1) {
|
||||
return (string) $this->parts[0];
|
||||
}
|
||||
|
||||
return $this->preSeparator . implode($this->separator, $this->parts) . $this->postSeparator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Expr;
|
||||
|
||||
/**
|
||||
* Expression class for DQL comparison expressions.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class Comparison
|
||||
{
|
||||
public const EQ = '=';
|
||||
public const NEQ = '<>';
|
||||
public const LT = '<';
|
||||
public const LTE = '<=';
|
||||
public const GT = '>';
|
||||
public const GTE = '>=';
|
||||
|
||||
/** @var mixed */
|
||||
protected $leftExpr;
|
||||
|
||||
/** @var string */
|
||||
protected $operator;
|
||||
|
||||
/** @var mixed */
|
||||
protected $rightExpr;
|
||||
|
||||
/**
|
||||
* Creates a comparison expression with the given arguments.
|
||||
*
|
||||
* @param mixed $leftExpr
|
||||
* @param string $operator
|
||||
* @param mixed $rightExpr
|
||||
*/
|
||||
public function __construct($leftExpr, $operator, $rightExpr)
|
||||
{
|
||||
$this->leftExpr = $leftExpr;
|
||||
$this->operator = $operator;
|
||||
$this->rightExpr = $rightExpr;
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
public function getLeftExpr()
|
||||
{
|
||||
return $this->leftExpr;
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getOperator()
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
public function getRightExpr()
|
||||
{
|
||||
return $this->rightExpr;
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function __toString()
|
||||
{
|
||||
return $this->leftExpr . ' ' . $this->operator . ' ' . $this->rightExpr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Expr;
|
||||
|
||||
use function implode;
|
||||
use function is_object;
|
||||
use function preg_match;
|
||||
|
||||
/**
|
||||
* Expression class for building DQL and parts.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class Composite extends Base
|
||||
{
|
||||
/** @return string */
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->count() === 1) {
|
||||
return (string) $this->parts[0];
|
||||
}
|
||||
|
||||
$components = [];
|
||||
|
||||
foreach ($this->parts as $part) {
|
||||
$components[] = $this->processQueryPart($part);
|
||||
}
|
||||
|
||||
return implode($this->separator, $components);
|
||||
}
|
||||
|
||||
/** @param string|object $part */
|
||||
private function processQueryPart($part): string
|
||||
{
|
||||
$queryPart = (string) $part;
|
||||
|
||||
if (is_object($part) && $part instanceof self && $part->count() > 1) {
|
||||
return $this->preSeparator . $queryPart . $this->postSeparator;
|
||||
}
|
||||
|
||||
// Fixes DDC-1237: User may have added a where item containing nested expression (with "OR" or "AND")
|
||||
if (preg_match('/\s(OR|AND)\s/i', $queryPart)) {
|
||||
return $this->preSeparator . $queryPart . $this->postSeparator;
|
||||
}
|
||||
|
||||
return $queryPart;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user