Skip to content

Commit

Permalink
feat: small improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
saade committed Feb 6, 2024
1 parent 76fb9e7 commit 3a50678
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 71 deletions.
56 changes: 32 additions & 24 deletions src/Forms/Components/AdjacencyList.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,41 +33,41 @@ protected function setUp(): void
}

$cachedExistingRecords = $component->getCachedExistingRecords();
$existingItemsIds = [];
$existingRecordsIds = [];

foreach ($state as $key => $item) {
$cb = function (array $items, array $item, string $key) use (&$cb, $component, $cachedExistingRecords, &$existingItemsIds) {
Arr::map(
$state,
$traverse = function (array $item, string $key, array $siblings = []) use (&$traverse, $component, $state, $cachedExistingRecords, &$existingRecordsIds): Model {
$relationship = $component->getRelationship();

$childrenKey = $component->getChildrenKey();
$recordKeyName = $relationship->getRelated()->getKeyName();
$recordKey = data_get($item, $recordKeyName);

// Update item order
if ($orderColumn = $component->getOrderColumn()) {
$item[$orderColumn] = array_search($key, array_keys($items));
$item[$orderColumn] = array_search($key, array_keys($siblings ?? $state));
}

// TODO: add ignore columns method
$data = Arr::except($item, [$recordKeyName, $childrenKey, 'path', 'depth']);
// Remove ignored columns
$data = Arr::except($item, $component->getIgnoredColumns());

// Update or create record
// Update or Create record
if ($record = $cachedExistingRecords->firstWhere($recordKeyName, $recordKey)) {
$record->fill($component->mutateRelationshipDataBeforeSave($data, $record));
} else {
$record = new ($component->getRelatedModel());
$record->fill($component->mutateRelationshipDataBeforeCreate($data));
}

// Update children
if ($relationship instanceof BelongsToMany) {
// if it's a many-to-many with pivot, we need to recursively walk down to the leaf nodes,
// potentially creating new nodes along the way, before we can then sync the children to the
// pivot on the way back up the tree.
// If it's a many-to-many with pivot, we need to recursively walk down to the
// leaf nodes potentially creating new nodes along the way, before we can
// then sync the children to the pivot on the way back up the tree.
$record->save();

if ($children = data_get($item, $childrenKey)) {
$childrenRecords = collect($children)
->map(fn ($child, $childKey) => $cb($children, $child, $childKey));
$childrenRecords = collect($children)->map(fn ($child, $childKey) => $traverse($child, $childKey, $children));

$record->{$childrenKey}()->syncWithPivotValues(
$childrenRecords->pluck($recordKeyName),
Expand All @@ -77,33 +77,29 @@ protected function setUp(): void
} else {
$record = $relationship->save($record);

// Update children
if ($children = data_get($item, $childrenKey)) {
$childrenRecords = collect($children)
->map(fn ($child, $childKey) => $cb($children, $child, $childKey));
$childrenRecords = collect($children)->map(fn ($child, $childKey) => $traverse($child, $childKey, $children));

$record->{$childrenKey}()->saveMany($childrenRecords);
}
}

// Update cached existing records
$cachedExistingRecords->push($record);
$existingItemsIds[] = $record->getKey();
// Do not delete this record
$existingRecordsIds[] = $recordKey;

return $record;
};

$cb($state, $item, $key);
}
}
);

// Delete removed records
$cachedExistingRecords
->filter(fn (Model $record) => ! in_array($record->getKey(), $existingItemsIds))
->reject(fn (Model $record) => in_array($record->getKey(), $existingRecordsIds))
->each(function (Model $record) use ($cachedExistingRecords) {
$record->delete();
$cachedExistingRecords->forget("record-{$record->getKey()}");
});

// Clear cache
$component->fillFromRelationship(cached: false);
});

Expand Down Expand Up @@ -132,4 +128,16 @@ public function getPivotAttributes(): ?array
{
return $this->evaluate($this->pivotAttributes);
}

public function getIgnoredColumns(): array
{
return [
'children',
'path',
'depth',
'created_at',
'updated_at',
'deleted_at',
];
}
}
110 changes: 63 additions & 47 deletions src/Forms/Components/NestedSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Kalnoy\Nestedset\DescendantsRelation;

class NestedSet extends Component
Expand All @@ -30,57 +31,59 @@ protected function setUp(): void
}

$cachedExistingRecords = $component->getCachedExistingRecords();
$existingItemsIds = [];

$data = collect($state)
->map(
$cb = function (array $item, string $key, array $children = []) use (&$cb, $component, $state, $cachedExistingRecords, &$existingItemsIds): array {
$relationship = $component->getRelationship();

$childrenKey = $component->getChildrenKey();
$recordKeyName = $relationship->getRelated()->getKeyName();
$recordKey = data_get($item, $recordKeyName);

// Update item order
if ($orderColumn = $component->getOrderColumn()) {
$item[$orderColumn] = array_search($key, array_keys($children ?: $state));
}

// TODO: add ignore columns method
$data = Arr::except($item, [$childrenKey, 'parent_id', '_lft', '_rgt', 'created_at', 'updated_at', 'deleted_at']);

// Update or create record
if ($record = $cachedExistingRecords->firstWhere($recordKeyName, $recordKey)) {
$data = $component->mutateRelationshipDataBeforeSave($data, $record);
} else {
$data = $component->mutateRelationshipDataBeforeCreate($data);
}

// Update children
if ($children = data_get($item, $childrenKey)) {
$data[$childrenKey] = collect($children)
->map(fn ($child, $childKey) => $cb($child, $childKey, $children))
->toArray();
}

// Update cached existing records
$existingItemsIds[] = $data[$recordKeyName];

return $data;
$existingRecordsIds = [];

$data = Arr::map(
$state,
$traverse = function (array $item, string $key, array $siblings = []) use (&$traverse, $component, $state, $cachedExistingRecords, &$existingRecordsIds): array {
$relationship = $component->getRelationship();
$childrenKey = $component->getChildrenKey();
$recordKeyName = $relationship->getRelated()->getKeyName();
$recordKey = data_get($item, $recordKeyName);

// Update item order
if ($orderColumn = $component->getOrderColumn()) {
$item[$orderColumn] = array_search($key, array_keys($siblings ?? $state));
}
)
->toArray();

$component->getRelatedModel()::rebuildTree($data);
// Remove ignored columns
$data = Arr::except($item, $component->getIgnoredColumns());

// Delete removed records
$cachedExistingRecords
->filter(fn (Model $record) => ! in_array($record->getKey(), $existingItemsIds))
->each(function (Model $record) use ($cachedExistingRecords) {
$record->delete();
$cachedExistingRecords->forget("record-{$record->getKey()}");
});
// Update or Create record
if ($record = $cachedExistingRecords->firstWhere($recordKeyName, $recordKey)) {
$data = $component->mutateRelationshipDataBeforeSave($data, $record);
} else {
$data = $component->mutateRelationshipDataBeforeCreate($data);
}

// Update children
if ($children = data_get($item, $childrenKey)) {
$data[$childrenKey] = Arr::map($children, fn ($child, $childKey) => $traverse($child, $childKey, $children));
}

// Do not delete this item
$existingRecordsIds[] = $recordKey;

return $data;
}
);

DB::transaction(
function () use ($component, $data, $existingRecordsIds, $cachedExistingRecords): void {
// Save tree
$component->getRelatedModel()::rebuildTree($data);

// Delete removed records
$cachedExistingRecords
->reject(fn (Model $record) => in_array($record->getKey(), $existingRecordsIds))
->each(function (Model $record) use ($cachedExistingRecords) {
$record->delete();
$cachedExistingRecords->forget("record-{$record->getKey()}");
});
}
);

// Clear cache
$component->fillFromRelationship(cached: false);
});

Expand All @@ -96,4 +99,17 @@ public function getChildrenKey(): string
{
return 'children';
}

public function getIgnoredColumns(): array
{
return [
'children',
'parent_id',
'_lft',
'_rgt',
'created_at',
'updated_at',
'deleted_at',
];
}
}

0 comments on commit 3a50678

Please sign in to comment.