How to avoid issues with step updates in upsertGroupedSteps caused by array reindexing when using dynamic fields? Livewire 3
I have a dynamic form fields logic in my Livewire 3 class:
public properties:
public $steps = [
['image' => null, 'text' => null],
];
public $step = ['image' => null, 'text' => null];
Add/Remove step logic:
public function removeStep($index): void
{
unset($this->steps[$index]);// unset step
$this->steps = array_values($this->steps); // reshuffle indexes after deleting
}
public function addStep(): void
{
$this->steps[] = $this->step;
}
After adding all the necessary steps, they should be saved in the guide_steps table:
guide_steps:
Schema::create('guide_steps', function (Blueprint $table) {
$table->id();
$table->foreignId('recipe_id')->constrained()->cascadeOnDelete();
$table->integer('step_number');
$table->text('step_text');
$table->string('step_image')->default('recipes-images/default/default_photo.png');
$table->timestamps();
$table->unique(['recipe_id', 'step_number']); // required for upsert()
});
Here is my approach for upserting new and updated steps, as well as removing steps that no longer exist in the new request:
upsertGroupedSteps:
public function upsertGroupedSteps($recipeId): void
{
$groupedSteps = collect($this->steps)->map(function ($step, $index) use ($recipeId){
return [
'recipe_id' => $recipeId,
'step_number' => $index + 1,
'step_text' => trim($step['text']),
'step_image' => $step['image']
? $step['image']->store('guides-images', 'public')
: 'recipes-images/default/default_photo.png',
'created_at' => now(),
'updated_at' => now(),
];
})->toArray();
// if recipeId != 0 it means we are updating existing steps
if ($this->recipeId != 0){
$newStepsNumbers = collect($groupedSteps)->pluck('step_number')->toArray();
GuideStep::where('recipe_id', $recipeId)
->whereNotIn('step_number', $newStepsNumbers)
->delete();
}
GuideStep::upsert(
$groupedSteps, ['recipe_id', 'step_number'], ['step_text', 'step_image']
);
}
Let’s say there are three steps with id 1, 2, 3 in the guide_steps table. When I delete the step with id 2, logically, steps with id 1 and 3 should remain. However, the step with id 3 gets deleted, and its data is overwritten into the step with id 2. I didn’t expect this behavior and am not sure if it’s correct.
Please or to participate in this conversation.