You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+102Lines changed: 102 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,6 +30,7 @@ conventions.
30
30
which alias is used for an entity when you are outside its creation context;
31
31
-**Lazy joins** to declare join statements to be performed only if related criteria are defined;
32
32
-**Immutable** and **unique** query **parameters**;
33
+
-**Proposals**: collect conditions, joins, parameters (and select/groupBy/orderBy/having) in a temporary object and merge them into the main query by using the proposal in `andWhere` / `orWhere`—ideal for strategies or filters that need to contribute a whole “block” of DQL;
33
34
- Works like magic ✨.
34
35
35
36
## Requirements
@@ -156,6 +157,107 @@ added to your DQL query only when you add **another condition/dql part** which r
156
157
Based on how confused you are right now, you can check [why you should need this](#why-do-i-need-this)
157
158
or [some examples](#examples) to achieve your "OMG" revelation moment.
158
159
160
+
### Proposals
161
+
162
+
When you split query building across multiple strategies or filter classes, you often want each one to contribute a **block** of logic: several conditions, joins, parameters, and maybe select/groupBy/orderBy/having. **Proposals** let you collect that block in a temporary object and “merge” it into the main `SharedQueryBuilder` in one go—by using the proposal inside `andWhere`, `orWhere`, `where`, `andHaving`, or `orHaving`. There is no separate `merge()` call: **merging happens when the proposal is used in one of those methods.**
163
+
164
+
#### Creating a proposal
165
+
166
+
Create an empty proposal from the `SharedQueryBuilder`; you can give it a name (useful for debugging) or leave it empty to get a unique auto-generated name.
// Anonymous proposal (unique name generated automatically)
173
+
$proposal = $sqb->createEmptyProposal();
174
+
```
175
+
176
+
#### Collect API (no side effects until use)
177
+
178
+
A proposal exposes the same method names as the SQB for building a **local** set of conditions, joins, parameters, and other parts. Nothing is written to the main query until the proposal is used in an expression.
-**Parameters**: use only `withUniqueImmutableParameter` on the proposal; on expansion, parameter names are made unique on the main SQB and the condition DQL is updated accordingly.
195
+
-**Nested proposals**: you can add another proposal as a condition: `$proposal->andWhere($nestedProposal)`. When the parent is expanded, nested proposals are expanded recursively.
196
+
197
+
#### Merging by use
198
+
199
+
To merge a proposal into the main query, pass it to `andWhere`, `orWhere`, `where`, `andHaving`, or `orHaving`. The SQB will expand the proposal (apply its joins, parameters, select/groupBy/orderBy/having, build the condition, and replace the proposal with the resulting DQL).
// Now the main query has the proposal’s condition and parameter; its joins/select/etc. would be applied too if we had added any.
209
+
```
210
+
211
+
You can combine multiple proposals in an OR (or AND) by expanding them first and passing the resulting strings to `expr()->orX()` (or `expr()->andX()`):
// Main query has (condition1 OR condition2) and both parameters.
225
+
```
226
+
227
+
#### Consumed state and reuse
228
+
229
+
After a proposal is expanded for the first time, it is marked **consumed**. Using the same proposal again in another `andWhere`/`orWhere` is a no-op: it expands to a neutral `1=1` so the query result is unchanged. Cloning a proposal gives a non-consumed copy with the same collected state.
0 commit comments