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
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
2. Company Regions Model
3. Company Regions Resource
<?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);
}
}
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(),
]);