@@ -98,36 +98,16 @@ public function searchRuleAction()
9898 }
9999 }
100100 }
101-
102- /* filter logic for mvc rules */
103- $ filter_funct_mvc = function ($ record ) use ($ categories , $ interfaces , $ show_all ) {
104- $ is_cat = empty ($ categories ) || array_intersect (explode (', ' , $ record ->categories ), $ categories );
105- $ rule_interfaces = $ record ->interface ->getValues ();
106-
107- // ALL rules, skip interface logic entirely
108- if ($ interfaces === null ) {
109- return $ is_cat ;
110- }
111-
112- if (!$ record ->interfacenot ->isEmpty ()) {
113- $ if_intersects = !array_intersect ($ interfaces , $ rule_interfaces ); /* All but interface */
114- } else {
115- $ if_intersects = array_intersect ($ interfaces , $ rule_interfaces );
116- }
117-
118- if (empty ($ interfaces )) {
119- $ is_if = count ($ rule_interfaces ) != 1 || !$ record ->interfacenot ->isEmpty ();
120- } elseif ($ show_all ) {
121- $ is_if = $ if_intersects || empty ($ rule_interfaces );
122- } elseif (!$ record ->interfacenot ->isEmpty ()) {
123- // Exclude as it should only be returned with show_all
124- $ is_if = false ;
125- } else {
126- // Include only an exact match, not a partial overlap
127- $ is_if = $ if_intersects && (count ($ interfaces ) == count ($ rule_interfaces ));
101+ /* extract all mvc records so we can filter and sort all at once */
102+ $ allrules = [];
103+ foreach ($ this ->getModel ()->rules ->rule ->iterateItems () as $ uuid => $ record ) {
104+ $ row = ['uuid ' => $ record ->getAttributes ()['uuid ' ]];
105+ $ reflen = strlen ($ record ->__reference ) + 1 ;
106+ foreach ($ record ->getFlatNodes () as $ key => $ val ) {
107+ $ row [substr ($ key , $ reflen )] = $ val ->getValue ();
128108 }
129- return $ is_cat && $ is_if ;
130- };
109+ $ allrules [] = $ row ;
110+ }
131111
132112 if ($ show_all ) {
133113 /* only query stats when fill info is requested */
@@ -136,39 +116,25 @@ public function searchRuleAction()
136116 $ rule_stats = [];
137117 }
138118
139-
140- $ filter_funct_rs = function (&$ record ) use ($ categories , $ interfaces , $ rule_stats ) {
141- /* always merge stats when found */
142- if (!empty ($ record ['uuid ' ]) && !empty ($ rule_stats [$ record ['uuid ' ]])) {
143- $ record = array_merge ($ record , $ rule_stats [$ record ['uuid ' ]]);
144- }
145- /* frontend can format aliases with an alias icon */
146- foreach (['source_net ' ,'source_port ' ,'destination_net ' ,'destination_port ' ] as $ field ) {
147- if (!empty ($ record [$ field ])) {
148- $ record ["alias_meta_ {$ field }" ] = $ this ->getNetworks ($ record [$ field ]);
149- }
150- }
151-
152- /* frontend can format categories with colors */
119+ $ filter_funct_rs = function (&$ record ) use ($ categories , $ interfaces , $ rule_stats ) {
120+ /* Filter criteria */
153121 $ r_categories = !empty ($ record ['categories ' ]) ? array_map ('trim ' , explode (', ' , $ record ['categories ' ])) : [];
154- $ record ['category_colors ' ] = $ this ->getCategoryColors ($ r_categories );
155-
156- if (empty ($ record ['legacy ' ])) {
157- /* mvc already filtered */
158- return true ;
159- }
160122 $ is_cat = empty ($ categories ) || array_intersect ($ r_categories , $ categories );
161-
162- if (!empty ($ record ['interfacenot ' ])) {
163- $ is_if = !array_intersect (explode (', ' , $ record ['interface ' ] ?? '' ), $ interfaces ?? []);
123+ $ rule_interfaces = array_filter (explode (', ' , $ record ['interface ' ] ?? '' ));
124+ if ($ interfaces === null || empty ($ record ['interface ' ])) {
125+ $ is_if = true ; // ALL interfaces or floating always matches
126+ } elseif (!empty ($ record ['interfacenot ' ])) {
127+ $ is_if = !array_intersect ($ rule_interfaces , $ interfaces ?? []);
164128 } else {
165- $ is_if = array_intersect (explode ( ' , ' , $ record [ ' interface ' ] ?? '' ) , $ interfaces ?? []);
129+ $ is_if = array_intersect ($ rule_interfaces , $ interfaces ?? []);
166130 }
167- // ALL interfaces or floating always matches
168- $ is_if = $ is_if || $ interfaces === null || empty ($ record ['interface ' ]);
169131
170- if ($ is_cat && $ is_if ) {
171- /* translate/convert legacy fields before returning, similar to mvc handling */
132+ if (!$ is_cat || !$ is_if ) {
133+ return false ; /* not reached */
134+ }
135+
136+ /* translate/convert legacy fields before returning, similar to mvc handling */
137+ if (!empty ($ record ['legacy ' ])) {
172138 foreach ($ this ->getLegacyFieldMap () as $ topic => $ data ) {
173139 if (!empty ($ record [$ topic ])) {
174140 $ tmp = [];
@@ -178,42 +144,42 @@ public function searchRuleAction()
178144 $ record [$ topic ] = implode (', ' , $ tmp );
179145 }
180146 }
181- // Tag legacy rules as "Automatic generated rules" if they have an empty category
182- if (!empty ($ record ['is_automatic ' ])) {
183- $ label = gettext ('Automatically generated rules ' );
184- $ record ['categories ' ] = $ label ; // Grouping key for tree view
185- $ record ['category_colors ' ] = [['name ' => $ label ]]; // Category formatter metadata
186- }
147+ }
187148
188- return true ;
189- } else {
190- return false ;
149+ /* Formatting */
150+
151+ /* always merge stats when found */
152+ if (!empty ($ record ['uuid ' ]) && !empty ($ rule_stats [$ record ['uuid ' ]])) {
153+ $ record = array_merge ($ record , $ rule_stats [$ record ['uuid ' ]]);
191154 }
192- };
193155
194- /**
195- * XXX: fetch mvc results first, we need to collect all to ensure proper pagination
196- * as pagination is passed using the request, we need to reset it temporary here as we don't know
197- * which page we need (yet) and don't want to duplicate large portions of code.
198- **/
199- $ ORG_REQ = $ _REQUEST ;
200- unset($ _REQUEST ['rowCount ' ]);
201- unset($ _REQUEST ['current ' ]);
202- if ($ show_all ) {
203- /* searchBase should not filter here since we later search for IP addresses in aliases */
204- unset($ _REQUEST ['searchPhrase ' ]);
205- }
206- $ filterset = $ this ->searchBase ("rules.rule " , null , "sort_order " , $ filter_funct_mvc )['rows ' ];
156+ // Tag legacy rules as "Automatic generated rules" if they have an empty category
157+ if (!empty ($ record ['is_automatic ' ])) {
158+ $ label = gettext ('Automatically generated rules ' );
159+ $ record ['categories ' ] = $ label ; // Grouping key for tree view
160+ $ record ['category_colors ' ] = [['name ' => $ label ]]; // Category formatter metadata
161+ }
162+
163+ /* frontend can format aliases with an alias icon */
164+ foreach (['source_net ' ,'source_port ' ,'destination_net ' ,'destination_port ' ] as $ field ) {
165+ if (!empty ($ record [$ field ])) {
166+ $ record ["alias_meta_ {$ field }" ] = $ this ->getNetworks ($ record [$ field ]);
167+ }
168+ }
169+
170+ /* frontend can format categories with colors */
171+ $ record ['category_colors ' ] = $ this ->getCategoryColors ($ r_categories );
172+ return true ;
173+ };
207174
208175 /* only fetch internal and legacy rules when 'show_all' is set */
209176 if ($ show_all ) {
210- $ otherrules = json_decode ((new Backend ())->configdRun ('filter list non_mvc_rules ' ), true ) ?? [];
211- } else {
212- $ otherrules = [];
177+ $ allrules = array_merge (
178+ $ allrules ,
179+ json_decode ((new Backend ())->configdRun ('filter list non_mvc_rules ' ), true ) ?? []
180+ );
213181 }
214182
215- $ _REQUEST = $ ORG_REQ ; /* XXX: fix me ?*/
216-
217183 $ search_clauses = [];
218184 $ backend = new Backend ();
219185 foreach (preg_split ('/\s+/ ' , (string )$ this ->request ->getPost ('searchPhrase ' , null , '' )) as $ token ) {
@@ -229,7 +195,7 @@ public function searchRuleAction()
229195 }
230196 }
231197 $ result = $ this ->searchRecordsetBase (
232- array_merge ( $ otherrules , $ filterset ) ,
198+ $ allrules ,
233199 null ,
234200 "sort_order " ,
235201 $ filter_funct_rs ,
0 commit comments