diff --git a/lib/Doctrine/ODM/MongoDB/Query/Expr.php b/lib/Doctrine/ODM/MongoDB/Query/Expr.php index bd9d8c079b..e924a66fc8 100644 --- a/lib/Doctrine/ODM/MongoDB/Query/Expr.php +++ b/lib/Doctrine/ODM/MongoDB/Query/Expr.php @@ -95,12 +95,7 @@ public function addAnd($expression, ...$expressions): self $this->query['$and'] = array_merge( $this->query['$and'], - array_map( - static function ($expression) { - return $expression instanceof Expr ? $expression->getQuery() : $expression; - }, - func_get_args() - ) + func_get_args() ); return $this; @@ -123,9 +118,7 @@ public function addNor($expression, ...$expressions): self $this->query['$nor'] = array_merge( $this->query['$nor'], - array_map(static function ($expression) { - return $expression instanceof Expr ? $expression->getQuery() : $expression; - }, func_get_args()) + func_get_args() ); return $this; @@ -148,9 +141,7 @@ public function addOr($expression, ...$expressions): self $this->query['$or'] = array_merge( $this->query['$or'], - array_map(static function ($expression) { - return $expression instanceof Expr ? $expression->getQuery() : $expression; - }, func_get_args()) + func_get_args() ); return $this; @@ -175,12 +166,8 @@ public function addOr($expression, ...$expressions): self */ public function addToSet($valueOrExpression): self { - if ($valueOrExpression instanceof Expr) { - $valueOrExpression = $valueOrExpression->getQuery(); - } - $this->requiresCurrentField(); - $this->newObj['$addToSet'][$this->currentField] = $valueOrExpression; + $this->newObj['$addToSet'][$this->currentField] = static::convertExpression($valueOrExpression, $this->class); return $this; } @@ -414,7 +401,7 @@ public function each(array $values): self */ public function elemMatch($expression): self { - return $this->operator('$elemMatch', $expression instanceof Expr ? $expression->getQuery() : $expression); + return $this->operator('$elemMatch', $expression); } /** @@ -601,7 +588,7 @@ public function getQuery(): array { return $this->dm->getUnitOfWork() ->getDocumentPersister($this->class->name) - ->prepareQueryOrNewObj($this->query); + ->prepareQueryOrNewObj($this->convertExpressions($this->query)); } /** @@ -878,7 +865,7 @@ public function nearSphere($x, $y = null): self */ public function not($expression): self { - return $this->operator('$not', $expression instanceof Expr ? $expression->getQuery() : $expression); + return $this->operator('$not', $expression); } /** @@ -978,12 +965,8 @@ public function position(int $position): self */ public function pull($valueOrExpression): self { - if ($valueOrExpression instanceof Expr) { - $valueOrExpression = $valueOrExpression->getQuery(); - } - $this->requiresCurrentField(); - $this->newObj['$pull'][$this->currentField] = $valueOrExpression; + $this->newObj['$pull'][$this->currentField] = static::convertExpression($valueOrExpression, $this->class); return $this; } @@ -1420,4 +1403,48 @@ private function wrapEqualityCriteria(): void $query = ['$in' => [$query]]; } + + private function convertExpressions(array $query, ?ClassMetadata $classMetadata = null): array + { + if ($classMetadata === null) { + $classMetadata = $this->class; + } + + $convertedQuery = []; + foreach ($query as $key => $value) { + if (is_string($key) && $classMetadata->hasAssociation($key)) { + $targetDocument = $classMetadata->getAssociationTargetClass($key); + + if ($targetDocument) { + $fieldMetadata = $this->dm->getClassMetadata($targetDocument); + } + } + + if (is_array($value)) { + $convertedQuery[$key] = $this->convertExpressions($value, $fieldMetadata ?? $classMetadata); + continue; + } + + $convertedQuery[$key] = static::convertExpression($value, $fieldMetadata ?? $classMetadata); + } + + return $convertedQuery; + } + + /** + * Converts expression objects to query arrays. Non-expression values are + * returned unmodified. + * + * @param Expr|mixed $expression + */ + private static function convertExpression($expression, ClassMetadata $classMetadata) + { + if (! $expression instanceof Expr) { + return $expression; + } + + $expression->setClassMetadata($classMetadata); + + return $expression->getQuery(); + } } diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH1674Test.php b/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH1674Test.php new file mode 100644 index 0000000000..71e4179207 --- /dev/null +++ b/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH1674Test.php @@ -0,0 +1,57 @@ +dm->createQueryBuilder(GH1674Document::class); + $builder + ->field('embedded') + ->elemMatch( + $builder->expr() + ->field('id') + ->equals(1) + ); + + $this->assertSame( + [ + 'embedded' => [ + '$elemMatch' => ['id' => '1'], + ], + ], + $builder->getQueryArray() + ); + } +} + +/** @ODM\Document */ +class GH1674Document +{ + /** @ODM\Id */ + protected $id; + + /** @ODM\EmbedMany(targetDocument=GH1674Embedded::class) */ + protected $embedded; + + public function __construct() + { + $this->id = new ObjectId(); + $this->embedded = new ArrayCollection(); + } +} + +/** @ODM\EmbeddedDocument */ +class GH1674Embedded +{ + /** @ODM\Field */ + public $id = []; +}