Skip to content

Commit fd93b75

Browse files
authored
Merge pull request #73 from imbus/fixes/datetests
Fixes/datetests
2 parents f9591c5 + e8dc2be commit fd93b75

File tree

9 files changed

+517
-990
lines changed

9 files changed

+517
-990
lines changed

app/Models/Asset.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,6 @@ protected function eolDate(): Attribute
389389

390390
}
391391

392-
393-
394392
protected function eolFormattedDate(): Attribute
395393
{
396394
return Attribute::make(

app/Services/FilterService/FilterService.php

Lines changed: 128 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -15,59 +15,43 @@
1515
class 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

Comments
 (0)