11
11
use ipl \Orm \Contract \QueryAwareBehavior ;
12
12
use ipl \Orm \Contract \RewriteColumnBehavior ;
13
13
use ipl \Orm \Query ;
14
+ use ipl \Stdlib \Data ;
14
15
use ipl \Stdlib \Filter ;
15
16
16
17
class FlattenedObjectVars implements RewriteColumnBehavior, QueryAwareBehavior
@@ -32,11 +33,39 @@ public function rewriteCondition(Filter\Condition $condition, $relation = null)
32
33
$ column = $ condition ->metaData ()->get ('columnName ' );
33
34
if ($ column !== null ) {
34
35
$ relation = substr ($ relation , 0 , -5 ) . 'customvar_flat. ' ;
35
- $ nameFilter = Filter::like ($ relation . 'flatname ' , $ column );
36
- $ class = get_class ($ condition );
37
- $ valueFilter = new $ class ($ relation . 'flatvalue ' , $ condition ->getValue ());
38
-
39
- return Filter::all ($ nameFilter , $ valueFilter );
36
+ $ condition ->metaData ()
37
+ ->set ('requiresTransformation ' , true )
38
+ ->set ('columnPath ' , $ relation . $ column )
39
+ ->set ('relationPath ' , substr ($ relation , 0 , -1 ));
40
+
41
+ // The ORM's FilterProcessor only optimizes filter conditions that are in the same level (chain).
42
+ // Previously, this behavior transformed a single condition to an ALL chain and hence the semantics
43
+ // of the level changed, since the FilterProcessor interpreted the conditions separately from there on.
44
+ // To not change the semantics of the condition it is required to delay the transformation of the condition
45
+ // until the subquery is created. Though, since the FilterProcessor only applies behaviors once, this
46
+ // hack is required. (The entire filter, metadata and optimization is total garbage.)
47
+ $ oldMetaData = $ condition ->metaData ();
48
+ $ reflection = new \ReflectionClass ($ condition );
49
+ $ reflection ->getProperty ('metaData ' )->setAccessible (true );
50
+ $ reflection ->getProperty ('metaData ' )->setValue ($ condition , new class () extends Data {
51
+ public function set ($ name , $ value )
52
+ {
53
+ if ($ name === 'behaviorsApplied ' ) {
54
+ return $ this ;
55
+ }
56
+
57
+ return parent ::set ($ name , $ value );
58
+ }
59
+ });
60
+ $ condition ->metaData ()->merge ($ oldMetaData );
61
+
62
+ // But to make it even worse: If we do that, (not transforming the condition) the FilterProcessor sees
63
+ // multiple conditions as targeting different columns, as it doesn't know that the *columns* are in fact
64
+ // custom variables. It then attempts to combine the conditions with an AND, which is not possible, since
65
+ // they refer to the same columns (flatname and flatvalue) after being transformed. So we have to make
66
+ // the condition refer to a different column, which is totally irrelevant, but since it's always the same
67
+ // column, the FilterProcessor won't attempt to combine the conditions. The literal icing on the cake.
68
+ $ condition ->setColumn ('always_the_same_but_totally_irrelevant ' );
40
69
}
41
70
}
42
71
0 commit comments