F
Filament15mo ago
Avriant

Help with prefecture->city logic, best practice

Full disclosure: inexperienced with Filament and PHP, but trying my best anyway. Want: user inputs a list of prefectures and cities it operates in. Then I can output it as a "user1/2/3 works here" kind of card grid on the Frontend. Have: messy code — tried one too many things and feel too lost at this point. I think I got confused because I ended up trying to do both things at the same time. Questions: 1. What is the best practice (scalabilitywise) for this type of logic? 2. Is it better to store prefecture/city IDs as JSON (array of IDs) or create a separate entry for each prefecture/city?
Code: 1. Migration
return new class extends Migration
Schema::create('company_regions', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(\App\Models\Company::class, 'company_id');
$table->foreignIdFor(\App\Models\City::class, 'city_id')->nullable();
$table->foreignIdFor(\App\Models\Prefectures::class, 'prefecture_id')->nullable();
// $table->json('associated_prefectures');
// $table->json('associated_cities');
$table->timestamps();
});
Schema::create('company_cities', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(\App\Models\Company::class, 'company_id');
$table->foreignIdFor(\App\Models\City::class, 'city_ids');
$table->timestamps();
});
Schema::create('company_prefectures', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(\App\Models\Company::class, 'company_id');
$table->foreignIdFor(\App\Models\Prefectures::class, 'prefecture_ids');
$table->timestamps();
});
return new class extends Migration
Schema::create('company_regions', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(\App\Models\Company::class, 'company_id');
$table->foreignIdFor(\App\Models\City::class, 'city_id')->nullable();
$table->foreignIdFor(\App\Models\Prefectures::class, 'prefecture_id')->nullable();
// $table->json('associated_prefectures');
// $table->json('associated_cities');
$table->timestamps();
});
Schema::create('company_cities', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(\App\Models\Company::class, 'company_id');
$table->foreignIdFor(\App\Models\City::class, 'city_ids');
$table->timestamps();
});
Schema::create('company_prefectures', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(\App\Models\Company::class, 'company_id');
$table->foreignIdFor(\App\Models\Prefectures::class, 'prefecture_ids');
$table->timestamps();
});
1 Reply
Avriant
AvriantOP15mo ago
2. Company Regions Model
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class CompanyRegions extends Model
{
use HasFactory;

protected $fillable = [
'company_id',
// 'city_ids',
// 'prefecture_ids',
'associated_prefectures',
'associated_cities',
];

// public function company(): BelongsTo
// {
// return $this->belongsTo(Company::class);
// }

// public function companyCities(): HasManyThrough
// {
// // return $this->through('city')->has('prefecture');
// return $this->hasManyThrough(City::class, Prefectures::class);
// }

public function cities(): BelongsToMany
{
return $this->belongsToMany(City::class);
}

public function prefectures(): BelongsToMany
{
return $this->belongsToMany(Prefectures::class);
}
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class CompanyRegions extends Model
{
use HasFactory;

protected $fillable = [
'company_id',
// 'city_ids',
// 'prefecture_ids',
'associated_prefectures',
'associated_cities',
];

// public function company(): BelongsTo
// {
// return $this->belongsTo(Company::class);
// }

// public function companyCities(): HasManyThrough
// {
// // return $this->through('city')->has('prefecture');
// return $this->hasManyThrough(City::class, Prefectures::class);
// }

public function cities(): BelongsToMany
{
return $this->belongsToMany(City::class);
}

public function prefectures(): BelongsToMany
{
return $this->belongsToMany(Prefectures::class);
}
}
3. Company Regions Resource
Company Regions Resource
<?php

namespace App\Filament\Resources;

use App\Filament\Resources\CompanyRegionsResource\Pages;
use App\Filament\Resources\CompanyRegionsResource\RelationManagers;
use App\Models\City;
use App\Models\CompanyRegions;
use App\Models\Prefectures;
use Filament\Forms;
use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;

class CompanyRegionsResource extends Resource
{
protected static ?string $model = CompanyRegions::class;

protected static ?string $navigationIcon = 'heroicon-o-collection';

protected static ?string $modelLabel = '地域選択';

public $prefectureId;
public $cityId;
Company Regions Resource
<?php

namespace App\Filament\Resources;

use App\Filament\Resources\CompanyRegionsResource\Pages;
use App\Filament\Resources\CompanyRegionsResource\RelationManagers;
use App\Models\City;
use App\Models\CompanyRegions;
use App\Models\Prefectures;
use Filament\Forms;
use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;

class CompanyRegionsResource extends Resource
{
protected static ?string $model = CompanyRegions::class;

protected static ?string $navigationIcon = 'heroicon-o-collection';

protected static ?string $modelLabel = '地域選択';

public $prefectureId;
public $cityId;
public static function form(Form $form): Form
{
return $form
->schema([
// Forms\Components\TextInput::make('company_id')
// ->required(),
// Forms\Components\Select::make('city_ids')
// ->relationship('cities', 'city_ja')
// ->searchable()
// ->multiple()
// ->helperText('Your full name here, including any middle names.')
// ->hint('[Forgotten your password?](forgotten-password)')
// ->required(),
// Forms\Components\TextInput::make('prefecture_ids')
// ->required(),
Forms\Components\Select::make('associated_prefectures')
->label('県名')
// ->relationship('prefectures', 'prefecture_ja')
->options(Prefectures::all()->pluck('prefecture_ja', 'id')->toArray())
->searchable()
->multiple()
->reactive()
->required()
->afterStateUpdated(fn (callable $set) => $set('cityId', null)),
public static function form(Form $form): Form
{
return $form
->schema([
// Forms\Components\TextInput::make('company_id')
// ->required(),
// Forms\Components\Select::make('city_ids')
// ->relationship('cities', 'city_ja')
// ->searchable()
// ->multiple()
// ->helperText('Your full name here, including any middle names.')
// ->hint('[Forgotten your password?](forgotten-password)')
// ->required(),
// Forms\Components\TextInput::make('prefecture_ids')
// ->required(),
Forms\Components\Select::make('associated_prefectures')
->label('県名')
// ->relationship('prefectures', 'prefecture_ja')
->options(Prefectures::all()->pluck('prefecture_ja', 'id')->toArray())
->searchable()
->multiple()
->reactive()
->required()
->afterStateUpdated(fn (callable $set) => $set('cityId', null)),
Forms\Components\Select::make('associated_cities')
->label('県名')
// ->relationship('cities', 'city_ja')
->options(function(callable $get) {
$prefecture = Prefectures::find($get('prefectureId'));

if (! $prefecture) {
return City::all()->pluck('city_ja', 'id');
}

return $prefecture->associated_cities->pluck('city_ja', 'id');

// $PrefectureName = $prefecture->associated_cities->pluck('city_ja', 'id');
// $PrefectureRegion = $prefecture->associated_cities->pluck('special_district_ja', 'id');

// return $PrefectureName . $PrefectureRegion;
})
->searchable()
->multiple()
->helperText('県全体対応でない場合ご記入ださい')
->hint('[Forgot your password?](forgotten-password)')
->required(),
// Forms\Components\Select::make('associated_prefectures')
// ->relationship('prefectures', 'prefecture_ja')
// ->searchable()
// ->multiple()
// ->required(),
// Forms\Components\Select::make('associated_cities')
// ->relationship('cities', 'city_ja')
// ->searchable()
// ->multiple()
// ->helperText('Your full name here, including any middle names.')
// ->hint('[Forgotten your password?](forgotten-password)')
// ->required(),
]);
Forms\Components\Select::make('associated_cities')
->label('県名')
// ->relationship('cities', 'city_ja')
->options(function(callable $get) {
$prefecture = Prefectures::find($get('prefectureId'));

if (! $prefecture) {
return City::all()->pluck('city_ja', 'id');
}

return $prefecture->associated_cities->pluck('city_ja', 'id');

// $PrefectureName = $prefecture->associated_cities->pluck('city_ja', 'id');
// $PrefectureRegion = $prefecture->associated_cities->pluck('special_district_ja', 'id');

// return $PrefectureName . $PrefectureRegion;
})
->searchable()
->multiple()
->helperText('県全体対応でない場合ご記入ださい')
->hint('[Forgot your password?](forgotten-password)')
->required(),
// Forms\Components\Select::make('associated_prefectures')
// ->relationship('prefectures', 'prefecture_ja')
// ->searchable()
// ->multiple()
// ->required(),
// Forms\Components\Select::make('associated_cities')
// ->relationship('cities', 'city_ja')
// ->searchable()
// ->multiple()
// ->helperText('Your full name here, including any middle names.')
// ->hint('[Forgotten your password?](forgotten-password)')
// ->required(),
]);
Want results from more Discord servers?
Add your server