Files
landing-api/app/Support/SiteUrls.php
Josep Piguillem 3897113313 Initial commit: Pireon Admin — headless admin panel and public API
Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer
collective, backed by the Pireon OAuth identity server. The public site is a
separate, server-rendered application consuming /api/public/v1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 17:55:27 +02:00

77 lines
2.2 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Support;
use Illuminate\Database\Eloquent\Model;
/**
* Builds the public-site URLs and hreflang alternates for a translatable
* record.
*
* This lives in the API rather than the frontend for one reason: only the API
* knows that `/ca/projectes/el-meu-projecte` and `/proyectos/mi-proyecto` are
* the same record. Without it the frontend cannot emit correct `hreflang`
* tags, and search engines treat the three languages as duplicates.
*/
final class SiteUrls
{
/**
* Every locale in which a record has a slug, mapped to its public path.
*
* @return array<string, string>
*/
public static function alternates(Model $record, string $type, string $slugField = 'slug'): array
{
$alternates = [];
foreach (array_keys(config('locales.supported')) as $locale) {
$slug = $record->getTranslation($slugField, $locale, useFallbackLocale: false);
// A locale without its own slug has no URL of its own — emitting
// one would advertise a page that does not exist.
if (blank($slug)) {
continue;
}
$alternates[$locale] = self::path($type, $locale, (string) $slug);
}
return $alternates;
}
/**
* Absolute URLs for the same set, ready to drop into `<link hreflang>`.
*
* @return array<string, string>
*/
public static function absoluteAlternates(Model $record, string $type, string $slugField = 'slug'): array
{
return array_map(
fn (string $path) => rtrim(config('site.url'), '/').$path,
self::alternates($record, $type, $slugField),
);
}
/**
* The path a record occupies on the public site, e.g. "/ca/projectes/foo".
*/
public static function path(string $type, string $locale, string $slug): string
{
$segments = [];
if ($locale !== config('locales.default') || config('site.prefix_default_locale')) {
$segments[] = $locale;
}
if ($prefix = config("site.paths.{$type}.{$locale}")) {
$segments[] = $prefix;
}
$segments[] = $slug;
return '/'.implode('/', array_filter($segments, fn ($s) => $s !== ''));
}
}