Skip to content

Instantly share code, notes, and snippets.

@websmithcode
Last active December 11, 2023 21:52
Show Gist options
  • Save websmithcode/16cefa4301fdeed7a497787f3d634311 to your computer and use it in GitHub Desktop.
Save websmithcode/16cefa4301fdeed7a497787f3d634311 to your computer and use it in GitHub Desktop.
FilamentPHP Composite address field

Subscribe to my telegram channel, don’t miss new interesting solutions

<?php
namespace App\Filament\Resources\Components;
use Filament\Forms\Components;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Set;
use Illuminate\Support\Str;
use LiveWire\Component as Livewire;
class AddressComponent extends Group
{
static $postfixes = [
'state' => ' область',
];
static $prefixes = [
'state' => '',
'city' => 'г.',
'street' => 'ул.',
'building' => 'д.',
'entrance' => 'п.',
'floor' => 'э.',
'apartment' => 'кв.',
];
public static function make(array|\Closure $schema = [], string $fieldName = 'address'): static
{
return parent::make($schema)
->schema([
Components\Hidden::make($fieldName)->live(),
Grid::make()->columns(3)->schema([
TextInput::make('state')->label('Область')->autofocus()->live(onBlur: true),
TextInput::make('city')->label('Город')->live(onBlur: true),
TextInput::make('street')->label('Улица')->live(onBlur: true),
]),
Grid::make()->columns(4)->schema([
TextInput::make('building')->label('Дом')->live(onBlur: true),
TextInput::make('entrance')->label('Подьезд')->live(onBlur: true),
TextInput::make('floor')->label('Этаж')->live(onBlur: true),
TextInput::make('apartment')->label('Квартира')->live(onBlur: true),
]),
])
->afterStateHydrated(function (Set $set, ?array $state, Livewire $livewire) use ($fieldName) {
foreach (AddressComponent::parseString($state[$fieldName]) as $key => $value) {
$set($key, $value);
}
})
->afterStateUpdated(function (Set $set, ?array $state) use ($fieldName) {
return $set('address', AddressComponent::toString($state, $fieldName));
});
}
static function toString(array $state, string $fieldName = 'address')
{
$parts = [
'state' => $state['state'],
'city' => $state['city'],
'street' => $state['street'],
'building' => $state['building'],
'entrance' => $state['entrance'],
'floor' => $state['floor'],
'apartment' => $state['apartment'],
];
$values = array_filter($parts, fn($value) => !empty($value));
if (isset($values['state']) && !str_contains(Str::of($values['state'])->trim(' ')->lower()->split('/[\s,]+/')->last(), 'обл')) {
$values['state'] = $values['state'] . AddressComponent::$postfixes['state'];
}
$address = collect($values)->map(function ($value, $key) {
return (string) Str::of($value)
->trim(' ')
->prepend(AddressComponent::$prefixes[$key], ' ');
})->implode(', ');
return $address;
}
static function parseString(?string $address)
{
if (empty($address))
return [];
$parts = explode(', ', $address);
// parse state by prefixes
$address = [];
foreach (AddressComponent::$prefixes as $key => $prefix) {
if ($key == 'state')
continue;
$address[$key] = '';
foreach ($parts as $part) {
if (str_contains($part, $prefix)) {
$address[$key] = (string) Str::of($part)->replace($prefix, '')->trim();
// remove parsed part
$parts = array_diff($parts, [$part]);
break;
}
}
}
if (empty($address['state'])) {
$address['state'] = array_pop($parts);
}
return $address;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment