This commit is contained in:
Dan Harrin
2024-02-07 10:33:16 +00:00
parent f53525e3ca
commit ae02253b4e
5 changed files with 169 additions and 34 deletions
@@ -36,6 +36,8 @@ trait HasState
protected bool | Closure $isDehydrated = true;
protected bool | Closure $isDehydratedWhenHidden = false;
protected ?string $statePath = null;
protected string $cachedAbsoluteStatePath;
@@ -135,6 +137,13 @@ trait HasState
return $this;
}
public function dehydratedWhenHidden(bool | Closure $condition = true): static
{
$this->isDehydratedWhenHidden = $condition;
return $this;
}
public function formatStateUsing(?Closure $callback): static
{
$this->afterStateHydrated(fn (Component $component) => $component->state($component->evaluate($callback)));
@@ -432,6 +441,20 @@ trait HasState
return (bool) $this->evaluate($this->isDehydrated);
}
public function isDehydratedWhenHidden(): bool
{
return (bool) $this->evaluate($this->isDehydratedWhenHidden);
}
public function isHiddenAndNotDehydrated(): bool
{
if (! $this->isHidden()) {
return false;
}
return ! $this->isDehydratedWhenHidden();
}
public function getGetCallback(): Get
{
return new Get($this);
@@ -78,8 +78,9 @@ class MorphToSelect extends Component
->options($selectedType?->getOptionsUsing)
->getSearchResultsUsing($selectedType?->getSearchResultsUsing)
->getOptionLabelUsing($selectedType?->getOptionLabelUsing)
->required($isRequired)
->hidden(! $selectedType)
->required(filled($selectedType))
->hidden(blank($selectedType))
->dehydratedWhenHidden()
->searchable($this->isSearchable())
->searchDebounce($this->getSearchDebounce())
->searchPrompt($this->getSearchPrompt())
@@ -99,28 +100,6 @@ class MorphToSelect extends Component
];
}
/**
* @param array<string, mixed> $state
*/
public function dehydrateState(array &$state, bool $isDehydrated = true): void
{
parent::dehydrateState($state, $isDehydrated);
if ($this->isRequired()) {
return;
}
$relationship = $this->getRelationship();
$typeColumn = $relationship->getMorphType();
$keyColumn = $relationship->getForeignKeyName();
$statePath = $this->getStatePath();
if (blank(data_get($state, "{$statePath}.{$typeColumn}"))) {
data_set($state, "{$statePath}.{$keyColumn}", null);
}
}
public function optionsLimit(int | Closure $limit): static
{
$this->optionsLimit = $limit;
+20 -4
View File
@@ -3,6 +3,7 @@
namespace Filament\Forms\Concerns;
use Filament\Forms\Components;
use Filament\Forms\Components\Component;
trait CanBeValidated
{
@@ -13,7 +14,11 @@ trait CanBeValidated
{
$attributes = [];
foreach ($this->getComponents() as $component) {
foreach ($this->getComponents(withHidden: true) as $component) {
if ($component->isHiddenAndNotDehydrated()) {
continue;
}
if ($component instanceof Components\Contracts\HasValidationRules) {
$component->dehydrateValidationAttributes($attributes);
}
@@ -40,7 +45,11 @@ trait CanBeValidated
{
$messages = [];
foreach ($this->getComponents() as $component) {
foreach ($this->getComponents(withHidden: true) as $component) {
if ($component->isHiddenAndNotDehydrated()) {
continue;
}
if ($component instanceof Components\Contracts\HasValidationRules) {
$component->dehydrateValidationMessages($messages);
}
@@ -67,7 +76,11 @@ trait CanBeValidated
{
$rules = [];
foreach ($this->getComponents() as $component) {
foreach ($this->getComponents(withHidden: true) as $component) {
if ($component->isHiddenAndNotDehydrated()) {
continue;
}
if ($component instanceof Components\Contracts\HasValidationRules) {
$component->dehydrateValidationRules($rules);
}
@@ -92,7 +105,10 @@ trait CanBeValidated
*/
public function validate(): array
{
if (! count($this->getComponents())) {
if (! count(array_filter(
$this->getComponents(withHidden: true),
fn (Component $component): bool => ! $component->isHiddenAndNotDehydrated(),
))) {
return [];
}
+6 -6
View File
@@ -70,8 +70,8 @@ trait HasState
*/
public function dehydrateState(array &$state = [], bool $isDehydrated = true): array
{
foreach ($this->getComponents() as $component) {
if ($component->isHidden()) {
foreach ($this->getComponents(withHidden: true) as $component) {
if ($component->isHiddenAndNotDehydrated()) {
continue;
}
@@ -87,8 +87,8 @@ trait HasState
*/
public function mutateDehydratedState(array &$state = []): array
{
foreach ($this->getComponents() as $component) {
if ($component->isHidden()) {
foreach ($this->getComponents(withHidden: true) as $component) {
if ($component->isHiddenAndNotDehydrated()) {
continue;
}
@@ -130,8 +130,8 @@ trait HasState
*/
public function mutateStateForValidation(array &$state = []): array
{
foreach ($this->getComponents() as $component) {
if ($component->isHidden()) {
foreach ($this->getComponents(withHidden: true) as $component) {
if ($component->isHiddenAndNotDehydrated()) {
continue;
}
+117
View File
@@ -440,6 +440,123 @@ test('components can be excluded from state dehydration if their parent componen
->dehydrateState()->toBe([]);
});
test('hidden components are excluded from state dehydration', function () {
$container = ComponentContainer::make(Livewire::make())
->statePath('data')
->components([
(new Component())
->statePath(Str::random())
->default(Str::random())
->hidden(),
])
->fill();
expect($container)
->dehydrateState()->toBe([]);
});
test('hidden components are excluded from state dehydration if their parent component is', function () {
$container = ComponentContainer::make(Livewire::make())
->statePath('data')
->components([
(new Component())
->hidden()
->schema([
(new Component())
->statePath(Str::random())
->default(Str::random()),
]),
])
->fill();
expect($container)
->dehydrateState()->toBe([]);
});
test('hidden components are excluded from state dehydration except if they are marked as dehydrated', function () {
$container = ComponentContainer::make(Livewire::make())
->statePath('data')
->components([
(new Component())
->statePath(Str::random())
->default(Str::random())
->hidden()
->dehydratedWhenHidden(),
])
->fill();
expect($container)
->dehydrateState()->not()->toBe([]);
});
test('disabled components are excluded from state dehydration', function () {
$container = ComponentContainer::make(Livewire::make())
->statePath('data')
->components([
(new Component())
->statePath(Str::random())
->default(Str::random())
->disabled(),
])
->fill();
expect($container)
->dehydrateState()->toBe([]);
});
test('disabled components are excluded from state dehydration if their parent component is', function () {
$container = ComponentContainer::make(Livewire::make())
->statePath('data')
->components([
(new Component())
->disabled()
->schema([
(new Component())
->statePath(Str::random())
->default(Str::random()),
]),
])
->fill();
expect($container)
->dehydrateState()->toBe([]);
});
test('disabled components are excluded from state dehydration except if they are marked as dehydrated', function () {
$container = ComponentContainer::make(Livewire::make())
->statePath('data')
->components([
(new Component())
->statePath(Str::random())
->default(Str::random())
->disabled()
->dehydrated(),
])
->fill();
expect($container)
->dehydrateState()->not()->toBe([]);
});
test('disabled components are excluded from state dehydration if their parent component is disabled and not marked as dehydrated', function () {
$container = ComponentContainer::make(Livewire::make())
->statePath('data')
->components([
(new Component())
->disabled()
->schema([
(new Component())
->statePath(Str::random())
->default(Str::random())
->dehydrated(),
]),
])
->fill();
expect($container)
->dehydrateState()->toBe([]);
});
test('dehydrated state can be mutated', function () {
$container = ComponentContainer::make(Livewire::make())
->statePath('data')