Files
SkinbaseNova/app/Support/Seo/BreadcrumbTrail.php

103 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Support\Seo;
use Illuminate\Support\Collection;
final class BreadcrumbTrail
{
/**
* @param iterable<mixed>|Collection<int, mixed>|null $breadcrumbs
* @return list<array{name: string, url: string}>
*/
public static function normalize(iterable|Collection|null $breadcrumbs): array
{
$items = collect($breadcrumbs instanceof Collection ? $breadcrumbs->all() : ($breadcrumbs ?? []))
->map(fn (mixed $crumb): ?array => self::mapCrumb($crumb))
->filter(fn (?array $crumb): bool => is_array($crumb) && $crumb['name'] !== '' && $crumb['url'] !== '')
->values();
$home = [
'name' => 'Home',
'url' => self::absoluteUrl('/'),
];
$normalized = [];
$seen = [];
foreach ($items as $crumb) {
$name = trim((string) ($crumb['name'] ?? ''));
$url = self::absoluteUrl((string) ($crumb['url'] ?? ''));
if ($name === '' || $url === '') {
continue;
}
if (self::isHome($name, $url)) {
$name = $home['name'];
$url = $home['url'];
}
$key = strtolower($name) . '|' . rtrim(strtolower($url), '/');
if (isset($seen[$key])) {
continue;
}
$seen[$key] = true;
$normalized[] = ['name' => $name, 'url' => $url];
}
if ($normalized === [] || ! self::isHome($normalized[0]['name'], $normalized[0]['url'])) {
array_unshift($normalized, $home);
}
return array_values($normalized);
}
/**
* @param mixed $crumb
* @return array{name: string, url: string}|null
*/
private static function mapCrumb(mixed $crumb): ?array
{
if (is_array($crumb)) {
return [
'name' => trim((string) ($crumb['name'] ?? '')),
'url' => trim((string) ($crumb['url'] ?? '')),
];
}
if (is_object($crumb)) {
return [
'name' => trim((string) ($crumb->name ?? '')),
'url' => trim((string) ($crumb->url ?? '')),
];
}
return null;
}
private static function isHome(string $name, string $url): bool
{
$normalizedUrl = rtrim(strtolower($url), '/');
$homeUrl = rtrim(strtolower(self::absoluteUrl('/')), '/');
return strtolower($name) === 'home' || $normalizedUrl === $homeUrl;
}
private static function absoluteUrl(string $url): string
{
$trimmed = trim($url);
if ($trimmed === '') {
return '';
}
if (preg_match('/^https?:\/\//i', $trimmed) === 1) {
return $trimmed;
}
return url($trimmed);
}
}