admin 管理员组

文章数量: 1086019

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, and 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.

Here's what's happening:

  • There were three steps numbered 1, 2, and 3.
  • I am removing step 2 using unset($this->steps[$index]), and then array_values(), which re-indexes the array.
  • As a result, step 3 becomes the second element of the array.
  • When I am calling upsertGroupedSteps(), the step_number now goes from 1 to N again (without gaps).
  • The query whereNotIn('step_number',$newStepsNumbers)->delete() deletes all steps whose step_numberdoesn't match.
  • Consequently, only the first and the new second steps remain in the table, and the third step is lost.

本文标签:

Error[2]: Invalid argument supplied for foreach(), File: /www/wwwroot/roclinux.cn/tmp/view_template_quzhiwa_htm_read.htm, Line: 58
File: /www/wwwroot/roclinux.cn/tmp/route_read.php, Line: 205, include(/www/wwwroot/roclinux.cn/tmp/view_template_quzhiwa_htm_read.htm)
File: /www/wwwroot/roclinux.cn/tmp/index.inc.php, Line: 129, include(/www/wwwroot/roclinux.cn/tmp/route_read.php)
File: /www/wwwroot/roclinux.cn/index.php, Line: 29, include(/www/wwwroot/roclinux.cn/tmp/index.inc.php)