pp-planer/app/Services/AgendaMatcherService.php

120 lines
3.9 KiB
PHP

<?php
namespace App\Services;
use App\Models\ServiceAgendaItem;
class AgendaMatcherService
{
/**
* Check if an item title matches a glob-style pattern.
* Supports * wildcard (matches any characters).
* Case-insensitive.
*/
public function matches(string $itemTitle, string $pattern): bool
{
$normalizedTitle = strtolower(trim($itemTitle));
$normalizedPattern = strtolower(trim($pattern));
return fnmatch($normalizedPattern, $normalizedTitle, FNM_CASEFOLD);
}
/**
* Check if an item title matches any of the patterns.
*
* @param array $patterns Array of glob-style patterns
*/
public function matchesAny(string $itemTitle, array $patterns): bool
{
foreach ($patterns as $pattern) {
if ($this->matches($itemTitle, $pattern)) {
return true;
}
}
return false;
}
/**
* Find the first ServiceAgendaItem whose title matches any of the patterns.
*
* @param array $agendaItems Array of ServiceAgendaItem
* @param string $patterns Comma-separated patterns (e.g. "Information*,Hinweis*")
*/
public function findFirstMatch(array $agendaItems, string $patterns): ?ServiceAgendaItem
{
$patternList = array_map(fn ($p) => trim($p), explode(',', $patterns));
$patternList = array_filter($patternList, fn ($p) => $p !== '');
foreach ($agendaItems as $item) {
if ($this->matchesAny($item->title, $patternList)) {
return $item;
}
}
return null;
}
/**
* Filter array of ServiceAgendaItems to only those between start and end boundary items.
* Boundary items are identified by matching start/end patterns (comma-separated strings).
* The boundary items themselves are EXCLUDED from the result.
*
* If startPattern is empty/null: start from the first item
* If endPattern is empty/null: go to the last item
*
* @param array $items Array of ServiceAgendaItem
* @param string|null $startPattern Comma-separated start patterns or null
* @param string|null $endPattern Comma-separated end patterns or null
* @return array Filtered items (boundaries excluded)
*/
public function filterBetween(array $items, ?string $startPattern, ?string $endPattern): array
{
if (empty($items)) {
return [];
}
$startIdx = 0;
$endIdx = count($items) - 1;
// Find start boundary index
if ($startPattern !== null && $startPattern !== '') {
$startItem = $this->findFirstMatch($items, $startPattern);
if ($startItem === null) {
// No matching start pattern — return empty
return [];
}
// Find the index of the start item
foreach ($items as $index => $item) {
if ($item->id === $startItem->id) {
$startIdx = $index + 1; // Exclude the boundary item
break;
}
}
}
// Find end boundary index
if ($endPattern !== null && $endPattern !== '') {
$endItem = $this->findFirstMatch($items, $endPattern);
if ($endItem === null) {
// No matching end pattern — return empty
return [];
}
// Find the index of the end item (search from end for clarity)
foreach (array_reverse($items, true) as $index => $item) {
if ($item->id === $endItem->id) {
$endIdx = $index - 1; // Exclude the boundary item
break;
}
}
}
// Return slice
if ($startIdx > $endIdx) {
return [];
}
return array_slice($items, $startIdx, $endIdx - $startIdx + 1);
}
}