Skip to content

Commit 7c6f90b

Browse files
Add createOptionForm
1 parent c81ff3f commit 7c6f90b

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed

src/SelectTree.php

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
namespace CodeWithDennis\FilamentSelectTree;
44

55
use Closure;
6+
use Exception;
7+
use Filament\Forms\ComponentContainer;
8+
use Filament\Forms\Components\Actions\Action;
69
use Filament\Forms\Components\Concerns\CanBeDisabled;
710
use Filament\Forms\Components\Concerns\CanBeSearchable;
811
use Filament\Forms\Components\Concerns\HasActions;
912
use Filament\Forms\Components\Concerns\HasAffixes;
1013
use Filament\Forms\Components\Concerns\HasPlaceholder;
1114
use Filament\Forms\Components\Contracts\HasAffixActions;
1215
use Filament\Forms\Components\Field;
16+
use Filament\Forms\Form;
17+
use Filament\Support\Facades\FilamentIcon;
1318
use Illuminate\Database\Eloquent\Relations\BelongsTo;
1419
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
1520
use Illuminate\Support\Collection;
@@ -58,6 +63,16 @@ class SelectTree extends Field implements HasAffixActions
5863

5964
protected Closure|array $hiddenOptions = [];
6065

66+
protected array | Closure | null $createOptionActionForm = null;
67+
68+
protected string | Closure | null $createOptionModalHeading = null;
69+
70+
protected ?Closure $modifyCreateOptionActionUsing = null;
71+
72+
protected ?Closure $modifyManageOptionActionsUsing = null;
73+
74+
protected ?Closure $createOptionUsing = null;
75+
6176
protected function setUp(): void
6277
{
6378
// Load the state from relationships using a callback function.
@@ -88,6 +103,20 @@ protected function setUp(): void
88103
$component->getRelationship()->sync($state->toArray());
89104
}
90105
});
106+
107+
$this->createOptionUsing(static function (SelectTree $component, array $data, Form $form) {
108+
$record = $component->getRelationship()->getRelated();
109+
$record->fill($data);
110+
$record->save();
111+
112+
$form->model($record)->saveRelationships();
113+
114+
return $record->getKey();
115+
});
116+
117+
$this->suffixActions([
118+
static fn (SelectTree $component): ?Action => $component->getCreateOptionAction(),
119+
]);
91120
}
92121

93122
private function buildTree(): Collection
@@ -369,4 +398,122 @@ public function getHiddenOptions(): array
369398
{
370399
return $this->evaluate($this->hiddenOptions);
371400
}
401+
402+
public function getCreateOptionActionForm(Form $form): array | Form | null
403+
{
404+
return $this->evaluate($this->createOptionActionForm, ['form' => $form]);
405+
}
406+
407+
public function hasCreateOptionActionFormSchema(): bool
408+
{
409+
return (bool) $this->createOptionActionForm;
410+
}
411+
412+
public function getCreateOptionModalHeading(): ?string
413+
{
414+
return $this->evaluate($this->createOptionModalHeading);
415+
}
416+
417+
public function manageOptionForm(array | Closure | null $schema): static
418+
{
419+
$this->createOptionForm($schema);
420+
421+
return $this;
422+
}
423+
424+
public function createOptionForm(array | Closure | null $schema): static
425+
{
426+
$this->createOptionActionForm = $schema;
427+
428+
return $this;
429+
}
430+
431+
public function getCreateOptionActionName(): string
432+
{
433+
return 'createOption';
434+
}
435+
436+
public function getCreateOptionUsing(): ?Closure
437+
{
438+
return $this->createOptionUsing;
439+
}
440+
441+
public function createOptionUsing(Closure $callback): static
442+
{
443+
$this->createOptionUsing = $callback;
444+
445+
return $this;
446+
}
447+
448+
public function getCreateOptionAction(): ?Action
449+
{
450+
if ($this->isDisabled()) {
451+
return null;
452+
}
453+
454+
if (! $this->hasCreateOptionActionFormSchema()) {
455+
return null;
456+
}
457+
458+
$action = Action::make($this->getCreateOptionActionName())
459+
->form(function (SelectTree $component, Form $form): array | Form | null {
460+
return $component->getCreateOptionActionForm($form->model(
461+
$component->getRelationship() ? $component->getRelationship()->getModel()::class : null,
462+
));
463+
})
464+
->action(static function (Action $action, array $arguments, SelectTree $component, array $data, ComponentContainer $form) {
465+
if (! $component->getCreateOptionUsing()) {
466+
throw new Exception("Select field [{$component->getStatePath()}] must have a [createOptionUsing()] closure set.");
467+
}
468+
469+
$createdOptionKey = $component->evaluate($component->getCreateOptionUsing(), [
470+
'data' => $data,
471+
'form' => $form,
472+
]);
473+
474+
$state = $component->getMultiple()
475+
? [
476+
...$component->getState(),
477+
$createdOptionKey,
478+
]
479+
: $createdOptionKey;
480+
481+
$component->state($state);
482+
$component->callAfterStateUpdated();
483+
484+
if (! ($arguments['another'] ?? false)) {
485+
return;
486+
}
487+
488+
$action->callAfter();
489+
490+
$form->fill();
491+
492+
$action->halt();
493+
})
494+
->color('gray')
495+
->icon(FilamentIcon::resolve('forms::components.select.actions.create-option') ?? 'heroicon-m-plus')
496+
->iconButton()
497+
->modalHeading($this->getCreateOptionModalHeading() ?? __('filament-forms::components.select.actions.create_option.modal.heading'))
498+
->modalSubmitActionLabel(__('filament-forms::components.select.actions.create_option.modal.actions.create.label'))
499+
->extraModalFooterActions(fn (Action $action, SelectTree $component): array => $component->getMultiple() ? [
500+
$action->makeModalSubmitAction('createAnother', arguments: ['another' => true])
501+
->label(__('filament-forms::components.select.actions.create_option.modal.actions.create_another.label')),
502+
] : []);
503+
504+
if ($this->modifyManageOptionActionsUsing) {
505+
$action = $this->evaluate($this->modifyManageOptionActionsUsing, [
506+
'action' => $action,
507+
]) ?? $action;
508+
}
509+
510+
if ($this->modifyCreateOptionActionUsing) {
511+
$action = $this->evaluate($this->modifyCreateOptionActionUsing, [
512+
'action' => $action,
513+
]) ?? $action;
514+
}
515+
516+
return $action;
517+
}
518+
372519
}

0 commit comments

Comments
 (0)