1515class FilterService
1616{
1717
18- public function searchByFilter ( $ query , $ filters ){
19- $ q = $ query ->where (
20- function (Builder $ query ) use ($ filters ){
21-
22- $ dateFields = [
23- 'purchase_date ' ,
24- 'asset_eol_date ' ,
25- 'created_at ' ,
26- 'updated_at ' ,
27- ];
28-
29- $ query = $ this ->applyDateRangeFilter ($ query , 'purchase_date ' , $ filters );
30- $ query = $ this ->applyDateRangeFilter ($ query , 'asset_eol_date ' , $ filters );
31- $ query = $ this ->applyDateRangeFilter ($ query , 'assets.created_at ' , $ filters );
32- $ query = $ this ->applyDateRangeFilter ($ query , 'assets.updated_at ' , $ filters );
33-
34- $ skipFields = [
35- 'purchase_date ' ,
36- 'asset_eol_date ' ,
37- 'created_at ' ,
38- 'updated_at ' ,
39- ];
40-
41- //changed to Array and loop through each item
42- foreach ($ filters as $ filterItem ) {
43- // this legacy part does break tests with new structure covers the tests we had
44- // if (!is_array($filterItem) || !isset($filterItem['field'])) {
45- // foreach ($filters as $key => $value){
46- // // if (is_string($key) && !is_array($value) && !in_array($key, $skipFields)) {
47- // // $filterObj = [
48- // // 'field' => $key,
49- // // 'value' => $value,
50- // // 'operator' => 'contains', // default
51- // // 'logic' => 'AND' // default
52- // // ];
53- // // $this->applySingleFilter($query, $filterObj);
54- // // }
55- // }
56- // break;
57- // }
58- if (!isset ($ filterItem ['field ' ], $ filterItem ['operator ' ], $ filterItem ['logic ' ], $ filterItem ['value ' ])) {
59- continue ;
60- }
61- if ($ filterItem ['value ' ] === ['' ]) {
62- continue ;
63- }
64- if (in_array ($ filterItem ['field ' ], $ skipFields )) {
65- continue ;
66- }
67- $ this ->applySingleFilter ($ query , $ filterItem );
18+ public function searchByFilter ($ query , $ filters )
19+ {
20+ $ q = $ query ->where (function (Builder $ query ) use ($ filters ) {
21+
22+ // 1) ZUERST strikt die Datumsfelder anwenden (keine LIKEs!)
23+ // - reine DATE-Spalten
24+ $ this ->applyDateRangeFilter ($ query , 'assets.purchase_date ' , $ filters , /* isDateTime */ false );
25+ $ this ->applyDateRangeFilter ($ query , 'assets.asset_eol_date ' , $ filters , /* isDateTime */ false );
26+
27+ // - DATETIME-Spalten (volle Tagesgrenzen)
28+ $ this ->applyDateRangeFilter ($ query , 'assets.created_at ' , $ filters , /* isDateTime */ true );
29+ $ this ->applyDateRangeFilter ($ query , 'assets.updated_at ' , $ filters , /* isDateTime */ true );
30+
31+ // Diese Felder nicht noch einmal als Textfilter behandeln
32+ $ skipFields = [
33+ 'purchase_date ' ,
34+ 'asset_eol_date ' ,
35+ 'created_at ' ,
36+ 'updated_at ' ,
37+ ];
38+
39+ // 2) Restliche Filter (Text, Relationen, etc.)
40+ foreach ($ filters as $ filterItem ) {
41+ if (!isset ($ filterItem ['field ' ], $ filterItem ['operator ' ], $ filterItem ['logic ' ], $ filterItem ['value ' ])) {
42+ continue ;
6843 }
44+ if ($ filterItem ['value ' ] === ['' ]) {
45+ continue ;
46+ }
47+ if (in_array ($ filterItem ['field ' ], $ skipFields , true )) {
48+ continue ;
49+ }
50+
51+ $ this ->applySingleFilter ($ query , $ filterItem );
6952 }
70- );
53+ });
54+
7155 return $ q ;
7256 }
7357
@@ -78,6 +62,7 @@ function(Builder $query) use ($filters){
7862 * @param array $filterObj keys: field, value, operator, logic
7963 * @return void
8064 */
65+
8166 protected function applySingleFilter (Builder &$ q , array $ filterObj )
8267 {
8368 $ fieldname = $ filterObj ['field ' ];
@@ -316,112 +301,128 @@ protected function applyCustomFieldFilter(Builder $query, array $filter)
316301 $ this ->applyWhereWithOperator ($ query , $ column , $ value , $ operator );
317302 }
318303
319- protected function applyRelationalValue (Builder $ q , $ value , string $ operator , array $ meta ): void
320- {
321- $ idField = $ meta ['id ' ] ?? null ;
322- $ nameField = $ meta ['name ' ] ?? null ;
323- $ column = $ meta ['column ' ] ?? null ;
324-
325- if ($ column ) {
326- $ this ->applyWhereWithOperator ($ q , $ column , $ value , $ operator );
327- return ;
328- }
304+ protected function applyRelationalValue (Builder $ q , $ value , string $ operator , array $ meta ): void
305+ {
306+ $ idField = $ meta ['id ' ] ?? null ;
307+ $ nameField = $ meta ['name ' ] ?? null ;
308+ $ column = $ meta ['column ' ] ?? null ;
329309
330- // Fallback safety check
331- if (!$ idField && !$ nameField ) {
332- return ;
333- }
334- $ values = is_array ($ value ) ? $ value : [$ value ];
310+ if ($ column ) {
311+ $ this ->applyWhereWithOperator ($ q , $ column , $ value , $ operator );
312+ return ;
313+ }
335314
336- $ ids = array_filter ($ values , 'is_int ' );
337- $ names = array_filter ($ values , 'is_string ' );
315+ // Fallback safety check
316+ if (!$ idField && !$ nameField ) {
317+ return ;
318+ }
319+ $ values = is_array ($ value ) ? $ value : [$ value ];
338320
339- $ q -> where ( function ( $ subQ ) use ( $ ids, $ names , $ idField , $ nameField , $ operator ) {
340- $ first = true ;
321+ $ ids = array_filter ( $ values , ' is_int ' );
322+ $ names = array_filter ( $ values , ' is_string ' ) ;
341323
342- // IDs only
343- if (!empty ($ ids )) {
344- if ($ first ) {
345- $ subQ ->whereIn ($ idField , $ ids );
346- $ first = false ;
347- } else {
348- $ subQ ->orWhereIn ($ idField , $ ids );
349- }
350- }
324+ $ q ->where (function ($ subQ ) use ($ ids , $ names , $ idField , $ nameField , $ operator ) {
325+ $ first = true ;
351326
352- // Names only
353- foreach ($ names as $ name ) {
354- if ($ first ) {
355- $ this ->applyWhereWithOperator ($ subQ , $ nameField , $ name , $ operator );
356- $ first = false ;
357- } else {
358- $ subQ ->orWhere (function ($ q ) use ($ nameField , $ name , $ operator ) {
359- $ this ->applyWhereWithOperator ($ q , $ nameField , $ name , $ operator );
360- });
327+ // IDs only
328+ if (!empty ($ ids )) {
329+ if ($ first ) {
330+ $ subQ ->whereIn ($ idField , $ ids );
331+ $ first = false ;
332+ } else {
333+ $ subQ ->orWhereIn ($ idField , $ ids );
334+ }
361335 }
362- }
363- });
364- }
365336
366- protected function applyWhereWithOperator ( Builder $ query , string $ column , $ value , string $ operator )
367- {
368- $ value = is_array ( $ value ) ? $ value : [ $ value ];
369-
370- if ( $ operator === ' equals ' ) {
371- $ query -> whereIn ( $ column , $ value );
372- } else { // contains
373- $ query -> where ( function ( $ q ) use ( $ column , $ value ) {
374- foreach ( $ value as $ v ) {
375- $ q -> orWhere ( $ column , ' LIKE ' , ' % ' . $ v . ' % ' );
337+ // Names only
338+ foreach ( $ names as $ name ) {
339+ if ( $ first ) {
340+ $ this -> applyWhereWithOperator ( $ subQ , $ nameField , $ name , $ operator );
341+ $ first = false ;
342+ } else {
343+ $ subQ -> orWhere ( function ( $ q ) use ( $ nameField , $ name , $ operator ) {
344+ $ this -> applyWhereWithOperator ( $ q , $ nameField , $ name , $ operator );
345+ });
346+ }
376347 }
377348 });
378349 }
379- }
350+
351+ protected function applyWhereWithOperator (Builder $ query , string $ column , $ value , string $ operator )
352+ {
353+ $ value = is_array ($ value ) ? $ value : [$ value ];
354+
355+ if ($ operator === 'equals ' ) {
356+ $ query ->whereIn ($ column , $ value );
357+ } else {
358+ $ query ->where (function ($ q ) use ($ column , $ value ) {
359+ foreach ($ value as $ v ) {
360+ $ q ->orWhere ($ column , 'LIKE ' , '% ' . $ v . '% ' );
361+ }
362+ });
363+ }
364+ }
380365
381366 /**
382- * Query builder scope to filter by a date range on a given field
383- *
384- * @param \Illuminate\Database\Eloquent\Builder $query Query builder instance
385- * @param string $field Database column name
386- * @param string $startKey Filter array key for start date
387- * @param string $endKey Filter array key for end date
388- * @param array $filter Filter array
367+ *
389368 *
390- * @return \Illuminate\Database\Eloquent\Builder Modified query builder
369+ * @param Builder $query
370+ * @param string $qualifiedField
371+ * @param array $filters
372+ * @param bool $isDateTime
391373 */
392- public function applyDateRangeFilter ($ query , $ field , $ filters )
374+
375+ public function applyDateRangeFilter ($ query , $ qualifiedField , $ filters , bool $ isDateTime = false )
393376 {
394377 $ start = null ;
395- $ end = null ;
378+ $ end = null ;
379+
380+ $ fieldNameOnly = \Illuminate \Support \Str::afterLast ($ qualifiedField , '. ' );
396381
397382 foreach ($ filters as $ filter ) {
398383 if (!isset ($ filter ['field ' ], $ filter ['value ' ]) || !is_array ($ filter ['value ' ])) {
399384 continue ;
400385 }
401-
402- // Normalize: Remove table prefix (e.g., 'assets.')
403- $ fieldNameOnly = Str::afterLast ($ field , '. ' );
404-
405386 if ($ filter ['field ' ] !== $ fieldNameOnly ) {
406387 continue ;
407388 }
408-
409- if (isset ($ filter ['value ' ]['startDate ' ])) {
389+ if (array_key_exists ('startDate ' , $ filter ['value ' ])) {
410390 $ start = $ filter ['value ' ]['startDate ' ];
411391 }
412-
413- if (isset ($ filter ['value ' ]['endDate ' ])) {
392+ if (array_key_exists ('endDate ' , $ filter ['value ' ])) {
414393 $ end = $ filter ['value ' ]['endDate ' ];
415394 }
416395 }
417-
418- if (!empty ( $ start) ) {
419- $ query -> whereDate ( $ field , ' >= ' , $ start ) ;
396+
397+ if (!$ start && ! $ end ) {
398+ return $ query ;
420399 }
421-
422- if (!empty ($ end )) {
423- $ query ->whereDate ($ field , '<= ' , $ end );
400+
401+ if ($ isDateTime ) {
402+
403+ if ($ start && $ end ) {
404+ $ query ->whereBetween ($ qualifiedField , [
405+ \Carbon \Carbon::parse ($ start )->startOfDay (),
406+ \Carbon \Carbon::parse ($ end )->endOfDay (),
407+ ]);
408+ } elseif ($ start ) {
409+ $ query ->where ($ qualifiedField , '>= ' , \Carbon \Carbon::parse ($ start )->startOfDay ());
410+ } elseif ($ end ) {
411+ $ query ->where ($ qualifiedField , '<= ' , \Carbon \Carbon::parse ($ end )->endOfDay ());
412+ }
413+ } else {
414+ if ($ start && $ end ) {
415+ $ query ->whereBetween ($ qualifiedField , [
416+ \Carbon \Carbon::parse ($ start )->toDateString (),
417+ \Carbon \Carbon::parse ($ end )->toDateString (),
418+ ]);
419+ } elseif ($ start ) {
420+ $ query ->whereDate ($ qualifiedField , '>= ' , \Carbon \Carbon::parse ($ start )->toDateString ());
421+ } elseif ($ end ) {
422+ $ query ->whereDate ($ qualifiedField , '<= ' , \Carbon \Carbon::parse ($ end )->toDateString ());
423+ }
424424 }
425+
425426 return $ query ;
426427 }
427- }
428+ }
0 commit comments