44
55use AppendIterator ;
66use ArrayIterator ;
7- use Icinga \Data \Filter \Filter ;
8- use Icinga \Data \Filter \FilterAnd ;
9- use Icinga \Data \Filter \FilterChain ;
10- use Icinga \Data \Filter \FilterExpression ;
11- use Icinga \Data \Filter \FilterOr ;
127use ipl \Orm \Query ;
138use ipl \Orm \Relation ;
149use ipl \Orm \UnionQuery ;
1510use ipl \Sql \Expression ;
11+ use ipl \Sql \Filter \Exists ;
12+ use ipl \Sql \Filter \NotExists ;
13+ use ipl \Stdlib \Filter ;
1614
1715class FilterProcessor extends \ipl \Sql \Compat \FilterProcessor
1816{
1917 protected $ baseJoins = [];
2018
2119 protected $ madeJoins = [];
2220
23- public static function apply (Filter $ filter , Query $ query )
21+ public static function apply (Filter \ Rule $ filter , Query $ query )
2422 {
2523 if ($ query instanceof UnionQuery) {
2624 foreach ($ query ->getUnions () as $ union ) {
@@ -30,11 +28,11 @@ public static function apply(Filter $filter, Query $query)
3028 return ;
3129 }
3230
33- if (! $ filter ->isEmpty ()) {
31+ if ($ filter instanceof Filter \Condition || ! $ filter ->isEmpty ()) {
3432 $ filter = clone $ filter ;
35- if (! $ filter-> isChain () ) {
33+ if (! $ filter instanceof Filter \Chain ) {
3634 // TODO: Quickfix, there's probably a better solution?
37- $ filter = Filter::matchAll ($ filter );
35+ $ filter = Filter::all ($ filter );
3836 }
3937
4038 $ processor = new static ();
@@ -58,24 +56,24 @@ public static function apply(Filter $filter, Query $query)
5856 }
5957 }
6058
61- protected function requireAndResolveFilterColumns (Filter $ filter , Query $ query )
59+ protected function requireAndResolveFilterColumns (Filter \ Rule $ filter , Query $ query )
6260 {
63- if ($ filter instanceof FilterExpression ) {
64- if ($ filter ->getExpression () === '* ' ) {
61+ if ($ filter instanceof Filter \Condition ) {
62+ if ($ filter ->getValue () === '* ' ) {
6563 // Wildcard only filters are ignored so stop early here to avoid joining a table for nothing
6664 return ;
6765 }
6866
6967 $ column = $ filter ->getColumn ();
70- if (isset ($ filter ->metaData )) {
71- $ column = $ filter ->metaData [ ' relationCol ' ] ;
68+ if (isset ($ filter ->relationCol )) {
69+ $ column = $ filter ->relationCol ;
7270 }
7371
7472 $ resolver = $ query ->getResolver ();
7573 $ baseTable = $ query ->getModel ()->getTableName ();
7674 $ column = $ resolver ->qualifyPath ($ column , $ baseTable );
7775
78- $ filter ->metaData [ ' column ' ] = $ column ;
76+ $ filter ->columnPath = $ column ;
7977
8078 list ($ relationPath , $ columnName ) = preg_split ('/\.(?=[^.]+$)/ ' , $ column );
8179
@@ -95,10 +93,10 @@ protected function requireAndResolveFilterColumns(Filter $filter, Query $query)
9593 $ subjectBehaviors = $ resolver ->getBehaviors ($ subject );
9694
9795 // Prepare filter as if it were final to allow full control for rewrite filter behaviors
98- $ filter ->setExpression ($ subjectBehaviors ->persistProperty ($ filter ->getExpression (), $ columnName ));
96+ $ filter ->setValue ($ subjectBehaviors ->persistProperty ($ filter ->getValue (), $ columnName ));
9997 $ filter ->setColumn ($ resolver ->getAlias ($ subject ) . '. ' . $ columnName );
100- $ filter ->metaData [ ' relationCol ' ] = $ columnName ;
101- $ filter ->metaData [ ' relationPath ' ] = $ path ;
98+ $ filter ->relationCol = $ columnName ;
99+ $ filter ->relationPath = $ path ;
102100
103101 $ rewrittenFilter = $ subjectBehaviors ->rewriteCondition ($ filter , $ path . '. ' );
104102 if ($ rewrittenFilter !== null ) {
@@ -111,69 +109,71 @@ protected function requireAndResolveFilterColumns(Filter $filter, Query $query)
111109 $ this ->madeJoins [$ relationPath ][] = $ filter ;
112110 }
113111 } else {
114- /** @var FilterChain $filter */
112+ /** @var Filter\Chain $filter */
115113
116114 $ subQueryFilters = [];
117- foreach ($ filter-> filters () as $ child ) {
118- /** @var Filter $child */
115+ foreach ($ filter as $ child ) {
116+ /** @var Filter\Rule $child */
119117 $ rewrittenFilter = $ this ->requireAndResolveFilterColumns ($ child , $ query );
120118 if ($ rewrittenFilter !== null ) {
121- $ filter ->replaceById ($ child-> getId () , $ rewrittenFilter );
119+ $ filter ->replace ($ child , $ rewrittenFilter );
122120 $ child = $ rewrittenFilter ;
123121 }
124122
125123 // We optimize only single expressions
126- if (isset ($ child ->metaData ) && $ child instanceof FilterExpression ) {
127- $ relationPath = $ child ->metaData [ ' relationPath ' ] ;
124+ if (isset ($ child ->relationPath ) && $ child instanceof Filter \Condition ) {
125+ $ relationPath = $ child ->relationPath ;
128126 if (
129127 $ relationPath !== $ query ->getModel ()->getTableName ()
130128 && ! isset ($ query ->getWith ()[$ relationPath ])
131129 ) {
132130 if (! $ query ->getResolver ()->isDistinctRelation ($ relationPath )) {
133- if (isset ($ child ->metaData [ ' original ' ] )) {
134- $ column = $ child ->metaData [ ' original ' ]-> metaData [ ' column ' ] ;
135- $ sign = $ child ->metaData [ ' original ' ]-> getSign () ;
131+ if (isset ($ child ->original )) {
132+ $ column = $ child ->original -> columnPath ;
133+ $ child = $ child ->original ;
136134 } else {
137135 $ column = $ child ->getColumn ();
138- $ sign = $ child ->getSign ();
139136 }
140137
141- $ subQueryFilters [$ sign ][$ column ][] = $ child ;
138+ $ subQueryFilters [get_class ( $ child ) ][$ column ][] = $ child ;
142139 }
143140 }
144141 }
145142 }
146143
147- foreach ($ subQueryFilters as $ sign => $ filterCombinations ) {
144+ foreach ($ subQueryFilters as $ conditionClass => $ filterCombinations ) {
148145 foreach ($ filterCombinations as $ column => $ filters ) {
149146 // The relation path must be the same for all entries
150- $ relationPath = $ filters [0 ]->metaData [ ' relationPath ' ] ;
147+ $ relationPath = $ filters [0 ]->relationPath ;
151148
152149 // In case the parent query also selects the relation we may not require a subquery.
153150 // Otherwise we form a cartesian product and get unwanted results back.
154151 $ selectedByParent = isset ($ query ->getWith ()[$ relationPath ]);
155152
156153 // Though, only single equal comparisons or those chained with an OR may be evaluated on the base
157- if ($ selectedByParent && $ sign !== '!= ' && (count ($ filters ) === 1 || $ filter instanceof FilterOr)) {
154+ if (
155+ $ selectedByParent && $ conditionClass !== Filter \Unequal::class
156+ && (count ($ filters ) === 1 || $ filter instanceof Filter \Any)
157+ ) {
158158 continue ;
159159 }
160160
161161 $ relation = $ query ->getResolver ()->resolveRelation ($ relationPath );
162162 $ subQuery = $ query ->createSubQuery ($ relation ->getTarget (), $ relationPath );
163163 $ subQuery ->columns ([new Expression ('1 ' )]);
164164
165- if ($ sign === ' != ' || $ filter instanceof FilterAnd ) {
165+ if ($ conditionClass === Filter \Unequal::class || $ filter instanceof Filter \All ) {
166166 $ targetKeys = join (', ' , array_values (
167167 $ subQuery ->getResolver ()->qualifyColumns (
168168 (array ) $ subQuery ->getModel ()->getKeyName (),
169169 $ subQuery ->getResolver ()->getAlias ($ subQuery ->getModel ())
170170 )
171171 ));
172172
173- if ($ sign !== ' != ' || $ filter instanceof FilterOr ) {
173+ if ($ conditionClass !== Filter \Unequal::class || $ filter instanceof Filter \Any ) {
174174 // Unequal (!=) comparisons chained with an OR are considered an XOR
175- $ count = count (array_unique (array_map (function (FilterExpression $ f ) {
176- return $ f ->getExpression ();
175+ $ count = count (array_unique (array_map (function (Filter \ Condition $ f ) {
176+ return $ f ->getValue ();
177177 }, $ filters )));
178178 } else {
179179 // Unequal (!=) comparisons are transformed to equal (=) ones. If chained with an AND
@@ -186,22 +186,24 @@ protected function requireAndResolveFilterColumns(Filter $filter, Query $query)
186186 }
187187
188188 foreach ($ filters as $ i => $ child ) {
189- if ($ sign === ' != ' ) {
189+ if ($ conditionClass === Filter \Unequal::class ) {
190190 // Unequal comparisons must be negated since the sub-query is an inverse of the outer one
191- if ($ child ->isExpression ()) {
192- $ filters [$ i ] = $ child ->setSign ('= ' );
193- $ filters [$ i ]->metaData = $ child ->metaData ;
191+ if ($ child instanceof Filter \Condition) {
192+ $ negation = Filter::equal ($ child ->getColumn (), $ child ->getValue ());
193+ $ negation ->relationCol = $ child ->relationCol ;
194+ $ negation ->columnPath = $ child ->columnPath ;
195+ $ negation ->relationPath = $ child ->relationPath ;
196+ $ filters [$ i ] = $ negation ;
194197 } else {
195- $ childId = $ child ->getId (); // Gets re-indexed otherwise
196- $ filters [$ i ] = Filter::not ($ child )->setId ($ childId );
198+ $ filters [$ i ] = Filter::none ($ child );
197199 }
198200 }
199201
200202 // Remove joins solely used for filter conditions
201203 foreach ($ this ->madeJoins as $ joinPath => &$ madeBy ) {
202204 $ madeBy = array_filter ($ madeBy , function ($ relationFilter ) use ($ child ) {
203- return $ child-> getId () !== $ relationFilter-> getId ()
204- && ! $ child ->hasId ($ relationFilter-> getId ( ));
205+ return $ child !== $ relationFilter
206+ && ( $ child instanceof Filter \Condition || ! $ child ->has ($ relationFilter ));
205207 });
206208
207209 if (empty ($ madeBy )) {
@@ -213,16 +215,16 @@ protected function requireAndResolveFilterColumns(Filter $filter, Query $query)
213215 }
214216 }
215217
216- $ filter ->removeId ($ child-> getId () );
218+ $ filter ->remove ($ child );
217219 }
218220
219- static ::apply (Filter::matchAny ( $ filters ), $ subQuery );
221+ static ::apply (Filter::any (... $ filters ), $ subQuery );
220222
221- $ filter -> addFilter ( new FilterExpression (
222- '' ,
223- ( $ sign === ' != ' ? ' NOT ' : '' ) . ' EXISTS ' ,
224- $ subQuery ->assembleSelect ()->resetOrderBy ()
225- ));
223+ if ( $ conditionClass === Filter \Unequal::class) {
224+ $ filter -> add ( new NotExists ( $ subQuery -> assembleSelect ()-> resetOrderBy ()));
225+ } else {
226+ $ filter -> add ( new Exists ( $ subQuery ->assembleSelect ()->resetOrderBy ()));
227+ }
226228 }
227229 }
228230 }
0 commit comments