1111use ipl \Orm \Contract \QueryAwareBehavior ;
1212use ipl \Orm \Contract \RewriteColumnBehavior ;
1313use ipl \Orm \Query ;
14+ use ipl \Stdlib \Data ;
1415use ipl \Stdlib \Filter ;
1516
1617class FlattenedObjectVars implements RewriteColumnBehavior, QueryAwareBehavior
@@ -32,11 +33,39 @@ public function rewriteCondition(Filter\Condition $condition, $relation = null)
3233 $ column = $ condition ->metaData ()->get ('columnName ' );
3334 if ($ column !== null ) {
3435 $ 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 ' );
4069 }
4170 }
4271
0 commit comments