Skip to content

Commit cf9c77a

Browse files
committed
Make CompositeExpression immutable
1 parent 8f3f4f2 commit cf9c77a

File tree

4 files changed

+36
-22
lines changed

4 files changed

+36
-22
lines changed

UPGRADE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
5. The `add()`, `getQueryPart()`, `getQueryParts()`, `resetQueryPart()` and `resetQueryParts()` methods are removed.
1010
6. For a `select()` query, the `getSQL()` method now throws an expression if no `SELECT` expressions have been provided.
1111

12+
## BC BREAK: `CompositeExpression` is now immutable
13+
14+
The `add()` and `addMultiple()` methods now return a new instance instead of mutating the current one.
15+
1216
## BC BREAK: `OCI8Statement::convertPositionalToNamedPlaceholders()` is removed.
1317

1418
The `OCI8Statement::convertPositionalToNamedPlaceholders()` method has been extracted to an internal utility class.

lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
namespace Doctrine\DBAL\Query\Expression;
66

77
use Countable;
8+
use function array_filter;
9+
use function array_values;
810
use function count;
911
use function implode;
1012

1113
/**
1214
* Composite expression is responsible to build a group of similar expression.
15+
*
16+
* This class is immutable.
1317
*/
1418
class CompositeExpression implements Countable
1519
{
@@ -43,47 +47,48 @@ class CompositeExpression implements Countable
4347
*/
4448
public function __construct(string $type, array $parts = [])
4549
{
46-
$this->type = $type;
47-
48-
$this->addMultiple($parts);
50+
$this->type = $type;
51+
$this->parts = array_values(array_filter($parts, static function ($part) {
52+
return ! ($part instanceof self && count($part) === 0);
53+
}));
4954
}
5055

5156
/**
52-
* Adds multiple parts to composite expression.
57+
* Returns a CompositeExpression with the given parts added.
5358
*
54-
* @param array<int, self|string> $parts
59+
* This instance is immutable and unaffected by this method call.
5560
*
56-
* @return $this
61+
* @param array<int, self|string> $parts
5762
*/
5863
public function addMultiple(array $parts = []) : self
5964
{
65+
$result = $this;
66+
6067
foreach ($parts as $part) {
61-
$this->add($part);
68+
$result = $result->add($part);
6269
}
6370

64-
return $this;
71+
return $result;
6572
}
6673

6774
/**
68-
* Adds an expression to composite expression.
75+
* Returns a CompositeExpression with the given part added.
6976
*
70-
* @param self|string $part
77+
* This instance is immutable and unaffected by this method call.
7178
*
72-
* @return $this
79+
* @param self|string $part
7380
*/
7481
public function add($part) : self
7582
{
76-
if (empty($part)) {
77-
return $this;
78-
}
79-
8083
if ($part instanceof self && count($part) === 0) {
8184
return $this;
8285
}
8386

84-
$this->parts[] = $part;
87+
$that = clone $this;
88+
89+
$that->parts[] = $part;
8590

86-
return $this;
91+
return $that;
8792
}
8893

8994
/**

tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public function testCount() : void
1818

1919
self::assertCount(1, $expr);
2020

21-
$expr->add('u.group_id = 2');
21+
$expr = $expr->add('u.group_id = 2');
2222

2323
self::assertCount(2, $expr);
2424
}
@@ -29,16 +29,21 @@ public function testAdd() : void
2929

3030
self::assertCount(1, $expr);
3131

32-
$expr->add(new CompositeExpression(CompositeExpression::TYPE_AND, []));
32+
$expr = $expr->add(new CompositeExpression(CompositeExpression::TYPE_AND, []));
3333

3434
self::assertCount(1, $expr);
3535

36-
$expr->add(new CompositeExpression(CompositeExpression::TYPE_OR, ['u.user_id = 1']));
36+
$expr = $expr->add(new CompositeExpression(CompositeExpression::TYPE_OR, ['u.user_id = 1']));
3737

3838
self::assertCount(2, $expr);
3939

40+
// test immutability
4041
$expr->add('u.user_id = 1');
4142

43+
self::assertCount(2, $expr);
44+
45+
$expr = $expr->add('u.user_id = 1');
46+
4247
self::assertCount(3, $expr);
4348
}
4449

tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function testAndX(array $parts, string $expected) : void
3838
$composite = $this->expr->andX();
3939

4040
foreach ($parts as $part) {
41-
$composite->add($part);
41+
$composite = $composite->add($part);
4242
}
4343

4444
self::assertEquals($expected, (string) $composite);
@@ -99,7 +99,7 @@ public function testOrX(array $parts, string $expected) : void
9999
$composite = $this->expr->orX();
100100

101101
foreach ($parts as $part) {
102-
$composite->add($part);
102+
$composite = $composite->add($part);
103103
}
104104

105105
self::assertEquals($expected, (string) $composite);

0 commit comments

Comments
 (0)