Installation
composer require tomatophp/filament-locations
Publish the package assets and migrations:
php artisan vendor:publish --provider="TomatoPHP\FilamentLocations\FilamentLocationsServiceProvider" --tag="filament-locations:migrations"
php artisan vendor:publish --provider="TomatoPHP\FilamentLocations\FilamentLocationsServiceProvider" --tag="filament-locations:config"
php artisan migrate
Run Seeder Seed the database with default locations data:
php artisan db:seed --class=FilamentLocationsSeeder
Register Resources
Add the provided Filament resources to your app/Providers/Filament/AdminPanelProvider.php:
public function panel(Panel $panel): Panel
{
return $panel
->resources([
\TomatoPHP\FilamentLocations\Resources\CountryResource::class,
\TomatoPHP\FilamentLocations\Resources\CityResource::class,
\TomatoPHP\FilamentLocations\Resources\AreaResource::class,
\TomatoPHP\FilamentLocations\Resources\LanguageResource::class,
\TomatoPHP\FilamentLocations\Resources\CurrencyResource::class,
]);
}
First Use Case
Access the Filament admin panel (/admin) and navigate to the Countries resource to view, create, or edit entries. Use the hierarchical relationship between Countries → Cities → Areas for location-based applications.
Hierarchical Data Management
belongsTo/hasMany relationships to fetch nested locations:
$country = Country::with(['cities.areas'])->find(1);
Multi-Language Support
Language resource includes ISO codes and names. Use it to localize your app:
$language = Language::where('iso', 'en')->first();
morphToMany relationship:
public function languages()
{
return $this->morphToMany(Language::class, 'translatable');
}
Currency Integration
Currency resource for financial applications (e.g., e-commerce):
$usd = Currency::where('code', 'USD')->first();
public function currency()
{
return $this->belongsTo(Currency::class);
}
Customizing Resources
use TomatoPHP\FilamentLocations\Resources\CountryResource;
class CustomCountryResource extends CountryResource
{
public static function form(Form $form): Form
{
return parent::form($form)
->columns(2)
->schema([
// Add custom fields here
TextInput::make('custom_field')->columnSpanFull(),
]);
}
}
API Endpoints
// In Filament API routes (e.g., routes/filament.php)
Filament::registerApiRoutes();
GET /api/admin/resources/countries
Seed Custom Data Override the seeder to add custom locations:
use TomatoPHP\FilamentLocations\Database\Seeders\FilamentLocationsSeeder;
class CustomSeeder extends FilamentLocationsSeeder
{
public function run()
{
parent::run();
// Add custom entries
City::create(['name' => 'My Custom City', 'country_id' => 1]);
}
}
Localization
Use the Language resource to dynamically switch app language:
$currentLanguage = Language::where('iso', app()->getLocale())->first();
Validation Validate location fields in forms:
use TomatoPHP\FilamentLocations\Rules\ValidCountry;
$form->schema([
TextInput::make('country_id')
->rules([new ValidCountry]),
]);
Performance
Country::with(['cities.areas'])->get();
Cache::remember('all_countries', now()->addHours(1), function () {
return Country::all();
});
Seeder Conflicts
--force cautiously:
php artisan db:seed --class=FilamentLocationsSeeder --force
if (!Country::exists()) {
parent::run();
}
Hierarchy Dependencies
$table->foreignId('country_id')->constrained()->cascadeOnDelete();
Filament Resource Conflicts
CountryResource), Filament will throw a ResourceAlreadyRegistered error.AdminPanelProvider:
$panel->resources([
// Ensure no duplicates
]);
JSON vs. Database Data
Missing Migrations
php artisan migrate:status
Permission Issues
AdminPanelProvider:
$panel->users([
\Filament\Panel\Contracts\User::class,
]);
Relationship Errors
City not found), check:
country_id exists).country_id vs CountryId).Custom Fields Add custom fields to resources without modifying the package:
class CustomCountryResource extends CountryResource
{
public static function table(Table $table): Table
{
return parent::table($table)
->columns([
// Add custom columns
TextColumn::make('custom_field'),
]);
}
}
Bulk Actions Use Filament’s bulk actions to manage locations (e.g., delete multiple cities):
public static function table(Table $table): Table
{
return parent::table($table)
->actions([
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}
Local Development
tinker to explore seeded data:
php artisan tinker
>>> \TomatoPHP\FilamentLocations\Models\Country::all();
Testing
public function tearDown(): void
{
Artisan::call('migrate:fresh --seed');
parent::tearDown();
}
Extending Models
Add methods to models (e.g., Country) in a service provider:
\TomatoPHP\FilamentLocations\Models\Country::macro('getFullName', function () {
return "Country: {$this->name}";
});
Performance for Large Datasets
Country::paginate(20);
name on cities).How can I help you explore Laravel packages today?