Skip to content

Commit

Permalink
Feature: Nested Pages (#13)
Browse files Browse the repository at this point in the history
* wip

* Update web.php

* fix: phpstan

* cache page urls

* imporve `PageResource`
  • Loading branch information
Z3d0X authored Oct 19, 2022
1 parent 1f03dda commit 8984d4b
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 11 deletions.
2 changes: 2 additions & 0 deletions resources/lang/en/page-resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
'title' => 'Title',
'slug' => 'Slug',
'layout' => 'Layout',
'parent' => 'Parent',
'url' => 'URL',
],

'actions' => [
Expand Down
3 changes: 2 additions & 1 deletion routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
BLADE,
['component' => $component, 'page' => $filamentFabricatorPage]
);
});
})
->where('filamentFabricatorPage', '.*');
});
}
38 changes: 38 additions & 0 deletions src/FilamentFabricatorManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Z3d0X\FilamentFabricator;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Z3d0X\FilamentFabricator\Layouts\Layout;
use Z3d0X\FilamentFabricator\Models\Page;
use Z3d0X\FilamentFabricator\PageBlocks\PageBlock;
Expand All @@ -23,6 +25,8 @@ class FilamentFabricatorManager

protected ?string $favicon = 'favicon.ico';

protected array $pageUrls = [];

public function __construct()
{
$this->pageBlocks = collect();
Expand Down Expand Up @@ -127,4 +131,38 @@ public function getPageModel(): string
{
return config('filament-fabricator.page-model') ?? Page::class;
}

public function getPageUrls(): array
{
return Cache::rememberForever('filament-fabricator::page-urls', function () {
$this->getPageModel()::query()
->select('id', 'slug', 'title')
->whereNull('parent_id')
->with('allChildren')
->get()
->each(fn (Model $page) => $this->setPageUrl($page));

return $this->pageUrls;
});
}

public function getPageUrlFromId(int $id, bool $prefixSlash = false): ?string
{
$url = $this->getPageUrls()[$id];

return ($url[0] !== '/' && $prefixSlash) ? "/{$url}" : $url;
}

protected function setPageUrl(Page $page, ?string $parentUrl = null): string
{
$pageUrl = $parentUrl ? $parentUrl . '/' . trim($page->slug, " \n\r\t\v\x00/") : trim($page->slug);

if (filled($page->children)) {
foreach ($page->children as $child) {
$this->setPageUrl($child, $pageUrl);
}
}

return $this->pageUrls[$page->id] = $pageUrl;
}
}
6 changes: 5 additions & 1 deletion src/FilamentFabricatorServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,12 @@ public function bootingPackage()
Route::bind('filamentFabricatorPage', function ($value) {
$pageModel = FilamentFabricator::getPageModel();

$pageUrls = FilamentFabricator::getPageUrls();

$pageId = array_search($value, $pageUrls);

return $pageModel::query()
->where('slug', $value)
->where('id', $pageId)
->firstOrFail();
});

Expand Down
24 changes: 24 additions & 0 deletions src/Models/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Cache;

/**
* @property-read int $id
Expand Down Expand Up @@ -31,4 +34,25 @@ class Page extends Model
'blocks' => 'array',
'parent_id' => 'integer',
];

protected static function booted()
{
static::saved(fn () => Cache::forget('filament-fabricator::page-urls'));
static::deleted(fn () => Cache::forget('filament-fabricator::page-urls'));
}

public function parent(): BelongsTo
{
return $this->belongsTo(Page::class, 'parent_id');
}

public function children(): HasMany
{
return $this->hasMany(Page::class, 'parent_id');
}

public function allChildren(): HasMany
{
return $this->children()->select('id', 'slug', 'title', 'parent_id')->with('children:id,slug,title,parent_id');
}
}
52 changes: 45 additions & 7 deletions src/Resources/PageResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
namespace Z3d0X\FilamentFabricator\Resources;

use Closure;
use Filament\Forms\Components\Actions\Action as FormAction;
use Filament\Forms\Components\Card;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Form;
Expand All @@ -17,8 +19,10 @@
use Filament\Tables\Columns\BadgeColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Illuminate\Validation\Rules\Unique;
use Z3d0X\FilamentFabricator\Facades\FilamentFabricator;
use Z3d0X\FilamentFabricator\Forms\Components\PageBuilder;
use Z3d0X\FilamentFabricator\Resources\PageResource\Pages;
Expand Down Expand Up @@ -50,14 +54,18 @@ public static function form(Form $form): Form
Card::make()
->columnSpan(1)
->schema([
Placeholder::make('page_url')
->visible(fn ($record) => filled($record))
->content(fn ($record) => FilamentFabricator::getPageUrlFromId($record?->id, true)),

TextInput::make('title')
->label(__('filament-fabricator::page-resource.labels.title'))
->afterStateUpdated(function (Closure $get, Closure $set, ?string $state, ?Model $record) {
if (! $get('is_slug_changed_manually') && filled($state) && blank($record)) {
$set('slug', Str::slug($state));
}
})
->debounce(500)
->debounce('500ms')
->required(),

Hidden::make('is_slug_changed_manually')
Expand All @@ -66,7 +74,7 @@ public static function form(Form $form): Form

TextInput::make('slug')
->label(__('filament-fabricator::page-resource.labels.slug'))
->unique(ignoreRecord: true)
->unique(ignoreRecord: true, callback: fn (Unique $rule, Closure $get) => $rule->where('parent_id', $get('parent_id')))
->afterStateUpdated(function (Closure $set) {
$set('is_slug_changed_manually', true);
})
Expand All @@ -77,6 +85,28 @@ public static function form(Form $form): Form
->options(FilamentFabricator::getLayouts())
->default('default')
->required(),

Select::make('parent_id')
->label(__('filament-fabricator::page-resource.labels.parent'))
->searchable()
->preload()
->reactive()
->suffixAction(
fn ($get, $context) => FormAction::make($context . '-parent')
->icon('heroicon-o-external-link')
->url(fn () => PageResource::getUrl($context, ['record' => $get('parent_id')]))
->openUrlInNewTab()
->visible(fn () => filled($get('parent_id')))
)
->relationship(
'parent',
'title',
function (Builder $query, $record) {
if (filled($record)) {
$query->where('id', '!=', $record->id);
}
}
),
]),
]);
}
Expand All @@ -90,15 +120,23 @@ public static function table(Table $table): Table
->searchable()
->sortable(),

TextColumn::make('slug')
->label(__('filament-fabricator::page-resource.labels.slug'))
->searchable()
->sortable(),
TextColumn::make('url')
->label(__('filament-fabricator::page-resource.labels.url'))
->toggleable()
->getStateUsing(fn ($record) => FilamentFabricator::getPageUrls()[$record->id] ?? null)
->url(fn ($record) => FilamentFabricator::getPageUrls()[$record->id] ?? null),

BadgeColumn::make('layout')
->label(__('filament-fabricator::page-resource.labels.layout'))
->toggleable()
->sortable()
->enum(FilamentFabricator::getLayouts()),

TextColumn::make('parent.title')
->label(__('filament-fabricator::page-resource.labels.parent'))
->toggleable(isToggledHiddenByDefault: true)
->formatStateUsing(fn ($state) => $state ?? '-')
->url(fn ($record) => filled($record->parent_id) ? PageResource::getUrl('edit', ['record' => $record->parent_id]) : null),
])
->filters([
SelectFilter::make('layout')
Expand All @@ -110,7 +148,7 @@ public static function table(Table $table): Table
EditAction::make(),
Action::make('visit')
->label(__('filament-fabricator::page-resource.actions.visit'))
->url(fn ($record) => '/' . $record->slug)
->url(fn ($record) => FilamentFabricator::getPageUrlFromId($record->id, true))
->icon('heroicon-o-external-link')
->openUrlInNewTab()
->color('success')
Expand Down
3 changes: 2 additions & 1 deletion src/Resources/PageResource/Pages/EditPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Filament\Pages\Actions;
use Filament\Pages\Actions\Action;
use Filament\Resources\Pages\EditRecord;
use Z3d0X\FilamentFabricator\Facades\FilamentFabricator;
use Z3d0X\FilamentFabricator\Resources\PageResource;

class EditPage extends EditRecord
Expand All @@ -18,7 +19,7 @@ protected function getActions(): array
Actions\DeleteAction::make(),
Action::make('visit')
->label(__('filament-fabricator::page-resource.actions.visit'))
->url('/' . $this->record->slug)
->url(fn () => FilamentFabricator::getPageUrlFromId($this->record->id, true))
->icon('heroicon-o-external-link')
->openUrlInNewTab()
->color('success')
Expand Down
3 changes: 2 additions & 1 deletion src/Resources/PageResource/Pages/ViewPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Filament\Pages\Actions;
use Filament\Pages\Actions\Action;
use Filament\Resources\Pages\ViewRecord;
use Z3d0X\FilamentFabricator\Facades\FilamentFabricator;
use Z3d0X\FilamentFabricator\Resources\PageResource;

class ViewPage extends ViewRecord
Expand All @@ -17,7 +18,7 @@ protected function getActions(): array
Actions\EditAction::make(),
Action::make('visit')
->label(__('filament-fabricator::page-resource.actions.visit'))
->url('/' . $this->record->slug)
->url(fn () => FilamentFabricator::getPageUrlFromId($this->record->id, true))
->icon('heroicon-o-external-link')
->openUrlInNewTab()
->color('success')
Expand Down

0 comments on commit 8984d4b

Please sign in to comment.