Skip to content

Instantly share code, notes, and snippets.

@Voltra
Last active November 26, 2023 11:26
Show Gist options
  • Save Voltra/191666f4af51e42528e54bfc682661e9 to your computer and use it in GitHub Desktop.
Save Voltra/191666f4af51e42528e54bfc682661e9 to your computer and use it in GitHub Desktop.
filament-fabricator with spatie/laravel-translatable
<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Str;
use Spatie\RouteAttributes\Attributes\Fallback;
use Spatie\RouteAttributes\Attributes\Get;
use Spatie\RouteAttributes\Attributes\Where;
use Z3d0X\FilamentFabricator\Facades\FilamentFabricator;
use Z3d0X\FilamentFabricator\Layouts\Layout;
use Z3d0X\FilamentFabricator\Models\Contracts\Page;
class FilamentFabricatorController extends Controller
{
#[Get('/{filamentFabricatorPage?}')]
#[Where('filamentFabricatorPage', '.*')]
#[Fallback]
public function renderPage(Page $filamentFabricatorPage = null): string
{
// Handle root (home) page
if (blank($filamentFabricatorPage)) {
$pageUrls = FilamentFabricator::getPageUrls();
$pageId = array_search('/', $pageUrls);
$pageId = preg_replace('/^(.*)-+/', '', $pageId);
$pageId = (int)$pageId;
/*$pageId = FilamentFabricator::getUrlToIdMapping()['/'] ?? -1;*/
/** @var Page $filamentFabricatorPage */
$filamentFabricatorPage = FilamentFabricator::getPageModel()::query()
->where('id', $pageId)
->firstOrFail();
}
/** @var ?class-string<Layout> $layout */
$layout = FilamentFabricator::getLayoutFromName($filamentFabricatorPage?->layout);
if (!isset($layout)) {
throw new \Exception("Filament Fabricator: Layout \"{$filamentFabricatorPage->layout}\" not found");
}
/** @var string $component */
$component = $layout::getComponent();
return Blade::render(
<<<'BLADE'
<x-dynamic-component
:component="$component"
:page="$page"
/>
BLADE,
['component' => $component, 'page' => $filamentFabricatorPage]
);
}
}
<?php
namespace App\Overrides;
use App\Models\Overrides\Page;
use Illuminate\Support\Str;
use Z3d0X\FilamentFabricator\Models\Contracts\Page as PageContract;
class FilamentFabricatorManager extends \Z3d0X\FilamentFabricator\FilamentFabricatorManager
{
/**
* URI -> Page.id
* @var array<string, string>
*/
protected array $pageUrlToId = [];
public function getUrlToIdMapping(): array {
$this->getPageUrls();
return $this->pageUrlToId;
}
protected function setPageUrl(Page|PageContract $page, string $parentUrl = null): string
{
$this->setPageLocaleUrl($page, 'en', $parentUrl);
return $this->setPageLocaleUrl($page, 'fr', $parentUrl);
}
protected function setPageLocaleUrl(Page|PageContract $page, string $locale, string $parentUrl = null): string {
$slug = $page->getTranslation('slug', $locale, false);
$pageUrl = $parentUrl ? $parentUrl . '/' . trim($slug, " \n\r\t\v\x00/") : trim($slug);
if (filled($page->allChildren)) {
foreach ($page->allChildren as $child) {
$this->setPageUrl($child, $pageUrl);
}
}
$url = Str::start($pageUrl, '/');
$this->pageUrlToId[$url] = $page->id;
return $this->pageUrls["{$locale}--{$page->id}"] = Str::start($pageUrl, '/');
}
public function getPageUrlFromId(int $id, bool $prefixSlash = false): ?string
{
$locale = App::getLocale();
$url = $this->getPageUrls()["{$locale}--{$id}"];
if ($routingPrefix = $this->getRoutingPrefix()) {
$url = Str::start($url, $routingPrefix);
}
return $url;
}
public function getPageModel(): string
{
return config('filament-fabricator.page-model') ?? Page::class;
}
}
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Symfony\Component\HttpFoundation\Response;
class LocaleDetector
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$path = $request->decodedPath();
if ($this->matchesLocale($path, 'en')) {
App::setLocale('en');
} else {
App::setLocale(App::getFallbackLocale());
}
return $next($request);
}
protected function matchesLocale(string $uri, string $locale): bool {
return $uri === $locale
|| str_starts_with($uri, "$locale/")
|| str_starts_with($uri, "/$locale/");
}
}
<?php
namespace App\Providers;
use App\Overrides\FilamentFabricatorManager;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Z3d0X\FilamentFabricator\Facades\FilamentFabricator;
class OverridesProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
$this->app->scoped(FilamentFabricatorManager::ID, FilamentFabricatorManager::class);
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot(): void
{
Route::bind('filamentFabricatorPage', function ($value) {
$value = Str::start($value, '/');
$pageUrls = FilamentFabricator::getPageUrls();
$pageId = array_search($value, $pageUrls);
$pageId = preg_replace('/^(.*)-+/', '', $pageId);
$pageId = (int)$pageId;
/*$pageId = FilamentFabricator::getUrlToIdMapping()[$value] ?? -1;*/
return FilamentFabricator::getPageModel()::query()
->where('id', $pageId)
->firstOrFail();
});
}
}
<?php
namespace App\Models\Overrides;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\App;
use Spatie\Translatable\HasTranslations;
class Page extends \Z3d0X\FilamentFabricator\Models\Page
{
use HasTranslations;
public array $translatable = [
'title',
'slug',
'blocks',
];
public function parent(): BelongsTo
{
return $this->belongsTo(static::class, 'parent_id');
}
public function children(): HasMany
{
return $this->hasMany(static::class, 'parent_id');
}
public function allChildren(): HasMany
{
return $this->hasMany(static::class, 'parent_id')
->select('id', 'slug', 'title', 'parent_id')
->with('allChildren:id,slug,title,parent_id');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment