Skip to content

Commit 351a5c5

Browse files
author
Adrian Miu
committed
Implemented groupCurrentWhere() to wrap current conditions in a group so one can add condition ON TOP of existing ones
1 parent 07fc155 commit 351a5c5

File tree

5 files changed

+100
-1
lines changed

5 files changed

+100
-1
lines changed

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
],
3838
"php-csfix": [
3939
"php php-cs-fixer.phar fix ./src --rules=@PSR2"
40+
],
41+
"build-docs": [
42+
"php docs/couscous.phar generate --target=build/docs/"
4043
]
4144
}
4245
}

docs/select.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,21 @@ $select->whereSprintf("publish_date <= NOW() AND parent_id = %s AND title LIKE %
110110
// SQL: publish_date <= NOW() and parent_id = 10 AND title LIKE '%ABC%' OR author_id = 20
111111
```
112112

113+
#### Grouping existing conditions
114+
115+
There are times when some piece of code generates some conditions for a query and later another piece of code (via events, callbacks or decorators) attach additional conditions that work on top of the current conditions.
116+
117+
```php
118+
$select->where('id', 10)
119+
->orWhere('id', 15);
120+
// SQL at this point: WHERE id = 10 OR id = 15
121+
122+
// later you restrict everything
123+
$select->groupCurrentWhere()
124+
->where('author_id', 1);
125+
// SQL: WHERE (id = 10 OR id = 15) AND author_id = 15
126+
```
127+
113128
## JOINs
114129

115130
```php

src/Clause/Where.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ public function endSet()
104104
return $this;
105105
}
106106

107+
public function groupCurrentWhere()
108+
{
109+
$this->where->groupCurrent();
110+
111+
return $this;
112+
}
113+
107114
public function resetWhere()
108115
{
109116
$this->where = new Conditions($this->bindings, 'WHERE');

src/Component/Conditions.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,22 @@ class Conditions extends Component
1616

1717
protected $list = [];
1818

19+
protected $openedGroups = 0;
20+
1921
public function __construct(Bindings $bindings, string $type)
2022
{
2123
$this->bindings = $bindings;
2224
$this->type = $type;
2325
}
2426

27+
public function groupCurrent()
28+
{
29+
if (! empty($this->list)) {
30+
array_unshift($this->list, '(');
31+
$this->list[] = ')';
32+
}
33+
}
34+
2535
public function and(string $column, $value = null, $condition = '='): void
2636
{
2737
$this->append('AND ', $this->buildExpression($column, $value, $condition));
@@ -45,11 +55,15 @@ public function orSprintf(string $format, ...$bindInline): void
4555
public function openGroup($type = 'AND')
4656
{
4757
$this->list[] = empty($this->list) ? '(' : $type . ' (';
58+
$this->openedGroups++;
4859
}
4960

5061
public function closeGroup()
5162
{
52-
$this->list[] = ')';
63+
if ($this->openedGroups > 0) {
64+
$this->list[] = ')';
65+
$this->openedGroups--;
66+
}
5367
}
5468

5569
protected function append(string $andor, string $expr): void
@@ -162,11 +176,20 @@ protected function buildExpression(string $column, $value = null, $condition = '
162176
return "$column $condition $bind";
163177
}
164178

179+
protected function ensureGroupsAreClosed()
180+
{
181+
if ($this->openedGroups > 0) {
182+
$this->list[] = str_repeat(')', $this->openedGroups);
183+
$this->openedGroups = 0;
184+
}
185+
}
186+
165187
public function build(): string
166188
{
167189
if (empty($this->list)) {
168190
return '';
169191
}
192+
$this->ensureGroupsAreClosed();
170193

171194
return PHP_EOL . $this->type . $this->indent($this->list);
172195
}

tests/SelectTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,57 @@ public function test_nested_conditions()
205205
], $select->getBindValues());
206206
}
207207

208+
209+
public function test_auto_closing_groups()
210+
{
211+
$select = $this->newSelect();
212+
$select->from('posts')
213+
->columns('*')
214+
->where('id', 10)
215+
->whereStartSet()
216+
->where('parent_id', 10)
217+
->orWhere('parent_id', 11);
218+
219+
$expectedStatement = <<<SQL
220+
SELECT
221+
*
222+
FROM
223+
posts
224+
WHERE
225+
id = :__1__
226+
AND (
227+
parent_id = :__2__
228+
OR parent_id = :__3__
229+
)
230+
SQL;
231+
232+
$this->assertSameStatement($expectedStatement, $select->getStatement());
233+
}
234+
235+
public function test_grouping_current_conditions()
236+
{
237+
$select = $this->newSelect();
238+
$select->from('posts')
239+
->columns('*')
240+
->where('id', 10)
241+
->orWhere('id', 11)
242+
->groupCurrentWhere()
243+
->where('title', 'abc');
244+
245+
$expectedStatement = <<<SQL
246+
SELECT
247+
*
248+
FROM
249+
posts
250+
WHERE
251+
(id = :__1__
252+
OR id = :__2__)
253+
AND title = :__3__
254+
SQL;
255+
256+
$this->assertSamestatement($expectedStatement, $select->getStatement());
257+
}
258+
208259
public function test_raw_conditions()
209260
{
210261
$select = $this->newSelect();

0 commit comments

Comments
 (0)