Add Blog Category Resource and CRUD Pages: Created BlogCategoryResource with associated pages for listing, creating, and editing blog categories. Implemented localization for all labels and messages. Enhanced BlogCategory model to specify foreign key for related blogs.

This commit is contained in:
Ümit Tunç
2025-11-06 17:48:20 -03:00
parent 7563577aa8
commit 68fd923b42
9 changed files with 462 additions and 1 deletions
@@ -0,0 +1,77 @@
<?php
namespace App\Filament\Admin\Resources\BlogCategories;
use App\Filament\Admin\Resources\BlogCategories\Pages\CreateBlogCategory;
use App\Filament\Admin\Resources\BlogCategories\Pages\EditBlogCategory;
use App\Filament\Admin\Resources\BlogCategories\Pages\ListBlogCategories;
use App\Filament\Admin\Resources\BlogCategories\Schemas\BlogCategoryForm;
use App\Filament\Admin\Resources\BlogCategories\Tables\BlogCategoriesTable;
use App\Models\BlogCategory;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use UnitEnum;
class BlogCategoryResource extends Resource
{
protected static ?string $model = BlogCategory::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedTag;
protected static UnitEnum|string|null $navigationGroup = 'Blog';
public static function getNavigationLabel(): string
{
return __('blog_category.navigation_label');
}
public static function getModelLabel(): string
{
return __('blog_category.model_label');
}
public static function getPluralModelLabel(): string
{
return __('blog_category.plural_model_label');
}
public static function form(Schema $schema): Schema
{
return BlogCategoryForm::configure($schema);
}
public static function table(Table $table): Table
{
return BlogCategoriesTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListBlogCategories::route('/'),
'create' => CreateBlogCategory::route('/create'),
'edit' => EditBlogCategory::route('/{record}/edit'),
];
}
public static function getRecordRouteBindingEloquentQuery(): Builder
{
return parent::getRecordRouteBindingEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Filament\Admin\Resources\BlogCategories\Pages;
use App\Filament\Admin\Resources\BlogCategories\BlogCategoryResource;
use Filament\Resources\Pages\CreateRecord;
class CreateBlogCategory extends CreateRecord
{
protected static string $resource = BlogCategoryResource::class;
public function getTitle(): string
{
return __('blog_category.create');
}
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('index');
}
protected function getCreatedNotificationTitle(): ?string
{
return __('blog_category.created_successfully');
}
}
@@ -0,0 +1,62 @@
<?php
namespace App\Filament\Admin\Resources\BlogCategories\Pages;
use App\Filament\Admin\Resources\BlogCategories\BlogCategoryResource;
use Filament\Actions\Action;
use Filament\Actions\DeleteAction;
use Filament\Actions\ForceDeleteAction;
use Filament\Actions\RestoreAction;
use Filament\Resources\Pages\EditRecord;
class EditBlogCategory extends EditRecord
{
protected static string $resource = BlogCategoryResource::class;
public function getTitle(): string
{
return __('blog_category.edit');
}
protected function getHeaderActions(): array
{
return [
Action::make('save')
->label(__('blog_category.save'))
->action('save')
->keyBindings(['mod+s'])
->color('primary')
->size('sm'),
Action::make('cancel')
->label(__('blog_category.cancel'))
->url($this->getResource()::getUrl('index'))
->color('gray')
->size('sm'),
DeleteAction::make()
->label(__('blog_category.delete'))
->size('sm'),
RestoreAction::make()
->label(__('blog_category.restore'))
->size('sm'),
ForceDeleteAction::make()
->label(__('blog_category.force_delete'))
->size('sm'),
];
}
protected function getFormActions(): array
{
return []; // Boş array döndürerek alt taraftaki form action'larını gizliyoruz
}
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('index');
}
protected function getSavedNotificationTitle(): ?string
{
return __('blog_category.updated_successfully');
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Filament\Admin\Resources\BlogCategories\Pages;
use App\Filament\Admin\Resources\BlogCategories\BlogCategoryResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListBlogCategories extends ListRecords
{
protected static string $resource = BlogCategoryResource::class;
public function getTitle(): string
{
return __('blog_category.title');
}
protected function getHeaderActions(): array
{
return [
CreateAction::make()
->label(__('blog_category.create')),
];
}
}
@@ -0,0 +1,70 @@
<?php
namespace App\Filament\Admin\Resources\BlogCategories\Schemas;
use Filament\Forms\Components\ColorPicker;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
class BlogCategoryForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->columns(2)
->schema([
Section::make(__('blog_category.general_section'))
->schema([
TextInput::make('name')
->label(__('blog_category.name_field'))
->required()
->maxLength(255)
->live(onBlur: true)
->afterStateUpdated(function (string $operation, $state, callable $set) {
if ($operation !== 'create') {
return;
}
$set('slug', \Str::slug($state));
}),
TextInput::make('slug')
->label(__('blog_category.slug_field'))
->required()
->maxLength(255)
->unique(ignoreRecord: true)
->rules(['alpha_dash'])
->helperText(__('blog_category.slug_helper')),
Textarea::make('description')
->label(__('blog_category.description_field'))
->rows(3)
->maxLength(1000)
->helperText(__('blog_category.description_helper'))
->columnSpanFull(),
ColorPicker::make('color')
->label(__('blog_category.color_field'))
->default('#3B82F6')
->helperText(__('blog_category.color_helper')),
TextInput::make('sort_order')
->label(__('blog_category.sort_order_field'))
->numeric()
->default(0)
->helperText(__('blog_category.sort_order_helper')),
Toggle::make('is_active')
->label(__('blog_category.is_active_field'))
->default(true)
->helperText(__('blog_category.is_active_helper'))
->columnSpanFull(),
])
->columnSpanFull()
->collapsible(false),
]);
}
}
@@ -0,0 +1,93 @@
<?php
namespace App\Filament\Admin\Resources\BlogCategories\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Actions\ForceDeleteBulkAction;
use Filament\Actions\RestoreBulkAction;
use Filament\Tables\Columns\ColorColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\ToggleColumn;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
class BlogCategoriesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
ColorColumn::make('color')
->label(__('blog_category.color_field')),
TextColumn::make('name')
->label(__('blog_category.name_field'))
->searchable()
->sortable()
->weight('bold'),
TextColumn::make('slug')
->label(__('blog_category.slug_field'))
->searchable()
->sortable()
->limit(30)
->color('gray'),
TextColumn::make('description')
->label(__('blog_category.description_field'))
->limit(50)
->wrap()
->toggleable(),
TextColumn::make('blogs_count')
->label(__('blog_category.blogs_count'))
->counts('blogs')
->sortable()
->alignCenter(),
TextColumn::make('sort_order')
->label(__('blog_category.sort_order_field'))
->sortable()
->alignCenter()
->toggleable(),
ToggleColumn::make('is_active')
->label(__('blog_category.is_active_field'))
->alignCenter(),
TextColumn::make('created_at')
->label(__('blog_category.table_created_at'))
->dateTime('d.m.Y H:i')
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->label(__('blog_category.table_updated_at'))
->dateTime('d.m.Y H:i')
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
TernaryFilter::make('is_active')
->label(__('blog_category.is_active_field')),
])
->recordActions([
EditAction::make()
->label(__('blog_category.edit')),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make()
->label(__('blog_category.delete')),
RestoreBulkAction::make()
->label(__('blog_category.restore')),
ForceDeleteBulkAction::make()
->label(__('blog_category.force_delete')),
]),
])
->defaultSort('sort_order');
}
}