mirror of
https://github.com/filamentphp/filament.git
synced 2026-10-24 23:35:30 +08:00
fix: Saving layout components with the same relationship multiple times
This commit is contained in:
@@ -22,6 +22,17 @@ trait BelongsToContainer
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
public function getRootContainer(): Schema
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
|
||||
while (($parentComponent = $container->getParentComponent()) !== null) {
|
||||
$container = $parentComponent->getContainer();
|
||||
}
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
public function getLivewire(): Component & HasSchemas
|
||||
{
|
||||
return $this->getContainer()->getLivewire();
|
||||
|
||||
+72
-6
@@ -11,6 +11,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||
use Illuminate\Support\Arr;
|
||||
use Livewire\Component as LivewireComponent;
|
||||
|
||||
trait EntanglesStateWithSingularRelationship
|
||||
@@ -27,9 +28,12 @@ trait EntanglesStateWithSingularRelationship
|
||||
|
||||
protected ?Closure $mutateRelationshipDataBeforeSaveUsing = null;
|
||||
|
||||
protected bool | Closure $hasRelationship = false;
|
||||
|
||||
public function relationship(string $name, bool | Closure $condition = true, string | Closure | null $relatedModel = null): static
|
||||
{
|
||||
$this->relationship = $name;
|
||||
$this->hasRelationship = $condition;
|
||||
$this->relatedModel = $relatedModel;
|
||||
$this->statePath($name);
|
||||
|
||||
@@ -39,33 +43,88 @@ trait EntanglesStateWithSingularRelationship
|
||||
$component->fillFromRelationship();
|
||||
});
|
||||
|
||||
$this->saveRelationshipsBeforeChildrenUsing(static function (Component | CanEntangleWithSingularRelationships $component, LivewireComponent & HasSchemas $livewire) use ($condition): void {
|
||||
$this->saveRelationshipsBeforeChildrenUsing(static function (Component | CanEntangleWithSingularRelationships $component, LivewireComponent & HasSchemas $livewire): void {
|
||||
// All layout components using this relationship should be saved together in this function.
|
||||
$componentsWithThisRelationship = [];
|
||||
|
||||
$findComponentsWithThisRelationship = function (Schema $schema) use ($component, &$componentsWithThisRelationship, &$findComponentsWithThisRelationship): void {
|
||||
foreach ($schema->getComponents(withActions: false, withHidden: true) as $childComponent) {
|
||||
if ($childComponent->isHidden() && (! $childComponent->shouldSaveRelationshipsWhenHidden())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($childComponent->getModel() !== $component->getModel()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($childComponent->getRecord() !== $component->getRecord()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
($childComponent instanceof CanEntangleWithSingularRelationships) &&
|
||||
($childComponent->getRelationshipName() === $component->getRelationshipName()) &&
|
||||
($childComponent->hasRelationship())
|
||||
) {
|
||||
$componentsWithThisRelationship[] = $childComponent;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($childComponent->getChildSchemas() as $schema) {
|
||||
$findComponentsWithThisRelationship($schema);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$findComponentsWithThisRelationship($component->getRootContainer());
|
||||
|
||||
// The first layout component using this relationship is the one that will save the relationship for all of them.
|
||||
if (Arr::first($componentsWithThisRelationship) !== $component) {
|
||||
return;
|
||||
}
|
||||
|
||||
$record = $component->getCachedExistingRecord();
|
||||
|
||||
if (! $component->evaluate($condition)) {
|
||||
if (! $component->hasRelationship()) {
|
||||
$record?->delete();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $component->getChildSchema()->getState(shouldCallHooksBefore: false);
|
||||
$data = [];
|
||||
|
||||
foreach ($componentsWithThisRelationship as $componentWithThisRelationship) {
|
||||
$data = [
|
||||
...$data,
|
||||
...$componentWithThisRelationship->getChildSchema()->getState(shouldCallHooksBefore: false),
|
||||
];
|
||||
}
|
||||
|
||||
$translatableContentDriver = $livewire->makeFilamentTranslatableContentDriver();
|
||||
|
||||
if ($record) {
|
||||
$data = $component->mutateRelationshipDataBeforeSave($data);
|
||||
foreach ($componentsWithThisRelationship as $componentWithThisRelationship) {
|
||||
$data = $componentWithThisRelationship->mutateRelationshipDataBeforeSave($data);
|
||||
}
|
||||
|
||||
$translatableContentDriver ?
|
||||
$translatableContentDriver->updateRecord($record, $data) :
|
||||
$record->fill($data)->save();
|
||||
|
||||
foreach ($componentsWithThisRelationship as $componentWithThisRelationship) {
|
||||
$componentWithThisRelationship->cachedExistingRecord($record);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$relationship = $component->getRelationship();
|
||||
$relatedModel = $component->getRelatedModel();
|
||||
|
||||
$data = $component->mutateRelationshipDataBeforeCreate($data);
|
||||
foreach ($componentsWithThisRelationship as $componentWithThisRelationship) {
|
||||
$data = $componentWithThisRelationship->mutateRelationshipDataBeforeCreate($data);
|
||||
}
|
||||
|
||||
if ($translatableContentDriver) {
|
||||
$record = $translatableContentDriver->makeRecord($relatedModel, $data);
|
||||
@@ -82,7 +141,9 @@ trait EntanglesStateWithSingularRelationship
|
||||
$relationship->save($record);
|
||||
}
|
||||
|
||||
$component->cachedExistingRecord($record);
|
||||
foreach ($componentsWithThisRelationship as $componentWithThisRelationship) {
|
||||
$componentWithThisRelationship->cachedExistingRecord($record);
|
||||
}
|
||||
});
|
||||
|
||||
$this->dehydrated(false);
|
||||
@@ -155,6 +216,11 @@ trait EntanglesStateWithSingularRelationship
|
||||
return $this->relationship;
|
||||
}
|
||||
|
||||
public function hasRelationship(): bool
|
||||
{
|
||||
return $this->evaluate($this->hasRelationship) && filled($this->getRelationshipName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string<Model>|null
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,10 @@ interface CanEntangleWithSingularRelationships
|
||||
|
||||
public function getRelationship(): BelongsTo | HasOne | MorphOne | null;
|
||||
|
||||
public function getRelationshipName(): ?string;
|
||||
|
||||
public function hasRelationship(): bool;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
|
||||
Reference in New Issue
Block a user