tomatophp/filament-types
Filament Types Manager lets you define and manage reusable “types” in your Laravel app database. Includes a ready-to-use Filament resource with filtering, icons, colors, and labels, plus a simple plugin config to register type groups for your models.
Installation
composer require tomatophp/filament-types
Publish the config and migrations (if needed):
php artisan vendor:publish --provider="TomatoPHP\FilamentTypes\FilamentTypesServiceProvider"
php artisan migrate
Basic Setup
Register the TypeResource in your app/Providers/Filament/AdminPanelProvider.php:
public function panel(Panel $panel): Panel
{
return $panel
->resources([
// ... other resources
\TomatoPHP\FilamentTypes\Resources\TypeResource::class,
]);
}
First Use Case: Define a Custom Type
Create a type model (e.g., app/Models/CustomType.php):
use TomatoPHP\FilamentTypes\Contracts\Type;
class CustomType implements Type
{
public static function getLabel(): string
{
return 'Custom Type';
}
public static function getSlug(): string
{
return 'custom_type';
}
}
Register it in config/filament-types.php:
'types' => [
\App\Models\CustomType::class,
],
Access the Admin Panel
Visit /admin/types to manage your custom type via Filament’s UI.
Defining Types
Type contract with getLabel() and getSlug().HasFields, HasValidation):
use TomatoPHP\FilamentTypes\Traits\HasFields;
class CustomType implements Type
{
use HasFields;
public static function getFields(): array
{
return [
\Filament\Forms\Components\TextInput::make('name')->required(),
];
}
}
Dynamic Field Management
getFields() to define form fields dynamically.Select, RichEditor) for rich UX:
public static function getFields(): array
{
return [
\Filament\Forms\Components\Select::make('status')
->options(['active', 'inactive'])
->required(),
];
}
Validation and Logic
getRules():
use TomatoPHP\FilamentTypes\Traits\HasValidation;
class CustomType implements Type
{
use HasValidation;
public static function getRules(): array
{
return [
'name' => 'required|max:255',
];
}
}
Integration with Models
morphTo relationship:
// In your model (e.g., Post.php)
public function type()
{
return $this->morphTo();
}
HasType trait for convenience:
use TomatoPHP\FilamentTypes\Traits\HasType;
class Post extends Model
{
use HasType;
}
Customizing the Resource
TypeResource class to modify behavior:
namespace App\Filament\Resources;
use TomatoPHP\FilamentTypes\Resources\TypeResource as BaseTypeResource;
class CustomTypeResource extends BaseTypeResource
{
protected static ?string $model = \App\Models\CustomType::class;
}
Bulk Actions and Filters
public static function getPages(): array
{
return [
'index' => Pages\ListTypes::route('/'),
'create' => Pages\CreateType::route('/create'),
// Add custom pages (e.g., for bulk actions)
'bulk' => Pages\BulkActions::route('/bulk'),
];
}
Handling Table Columns with Icons
use Filament\Tables\Columns\IconColumn;
public static function tableColumns(): array
{
return [
IconColumn::make('icon')
->boolean()
->default(false) // Fallback for empty icons
->label('Has Icon'),
];
}
Type Registration
config/filament-types.php under the types key.php artisan config:clear if changes aren’t reflected.Field Conflicts
->columnSpanFull() for complex layouts:
TextInput::make('description')->columnSpanFull(),
Migration Conflicts
types table. Use php artisan migrate:fresh in development if needed.Caching
php artisan filament:cache:clear
Permission Handling
TypeResource:
protected static ?string $navigationIcon = 'heroicon-o-collection';
protected static ?string $navigationGroup = 'Settings';
protected static bool $shouldRegisterNavigation = true;
Table Icons in v4.0.2
IconColumn:
IconColumn::make('icon')->default('heroicon-o-circle'),
Reusable Type Logic
MediaType, UserRoleType) and extend them:
class MediaType implements Type
{
use HasFields, HasValidation;
public static function getFields(): array
{
return [
\Filament\Forms\Components\FileUpload::make('file')->image(),
];
}
}
Dynamic Type Selection
type() relationship to dynamically fetch type-specific data:
// In a Filament widget or page
$type = $record->type;
$fields = $type::getFields();
Localization
public static function getLabel(): string
{
return trans('types.custom_type.label');
}
Testing
use TomatoPHP\FilamentTypes\Tests\CreatesTypes;
class TypeTest extends TestCase
{
use CreatesTypes;
/** @test */
public function it_manages_custom_types()
{
$this->actingAsAdmin();
$this->createType(\App\Models\CustomType::class, ['name' => 'Test']);
$this->assertDatabaseHas('types', ['slug' => 'custom_type']);
}
}
Performance
$types = Type::with('model')->get();
defaultSort in the resource to optimize listing:
protected static ?string $defaultSort = 'created_at desc';
Extending the Package
public static function getBulkActions(): array
{
return [
\TomatoPHP\FilamentTypes\Actions\ExportTypesAction::make(),
];
}
use TomatoPHP\FilamentTypes\Widgets\TypeStatsWidget;
public static function getWidgets(): array
{
return [
TypeStatsWidget::class,
];
}
How can I help you explore Laravel packages today?