} $attributes */ public function handle(ProjectTemplate $projectTemplate, array $attributes): ProjectTemplate { return DB::transaction(function () use ($projectTemplate, $attributes): ProjectTemplate { $projectTemplate = ProjectTemplate::query()->whereKey($projectTemplate->id)->lockForUpdate()->firstOrFail(); $previousConfiguration = $this->duplicateProjectConfiguration->normalizeConfiguration($projectTemplate->configuration_snapshot ?? []); $copyAreas = $this->duplicateProjectConfiguration->normalizeCopyAreas(Arr::get($attributes, 'copy_areas', $projectTemplate->copy_areas ?? [])); $nextConfiguration = collect($this->duplicateProjectConfiguration->normalizeConfiguration( Arr::get($attributes, 'configuration_snapshot', $previousConfiguration), ))->only($copyAreas)->all(); $affectedAreas = collect(array_unique([...array_keys($previousConfiguration), ...array_keys($nextConfiguration)])) ->filter(fn (string $area): bool => ($previousConfiguration[$area] ?? null) !== ($nextConfiguration[$area] ?? null)) ->values()->all(); $projectTemplate->forceFill([ 'name' => Arr::get($attributes, 'name'), 'copy_areas' => $copyAreas, 'configuration_snapshot' => $nextConfiguration, ])->save(); Project::query() ->where('project_template_id', $projectTemplate->id) ->orderBy('id') ->chunkById(100, function ($linkedProjects) use ($projectTemplate, $affectedAreas, $nextConfiguration, $previousConfiguration): void { foreach ($linkedProjects as $linkedProject) { $linkedProject = Project::query() ->whereKey($linkedProject->id) ->where('project_template_id', $projectTemplate->id) ->lockForUpdate()->first(); if ($linkedProject === null) { continue; } $currentConfiguration = $this->duplicateProjectConfiguration->export($linkedProject, $affectedAreas); $overrides = $linkedProject->template_overrides ?? []; $replacementConfiguration = []; foreach ($affectedAreas as $area) { if (in_array($area, $overrides, true)) { continue; } if (! array_key_exists($area, $nextConfiguration)) { $this->projectTemplateOverrideManager->mark($linkedProject, $area); continue; } if (! array_key_exists($area, $previousConfiguration) && array_key_exists($area, $currentConfiguration) && $currentConfiguration[$area] !== []) { $this->projectTemplateOverrideManager->mark($linkedProject, $area); continue; } $replacementConfiguration[$area] = $nextConfiguration[$area]; } if ($replacementConfiguration !== []) { $this->duplicateProjectConfiguration->apply($linkedProject, $replacementConfiguration); } } }); return $projectTemplate->fresh(['sourceProject'])->loadCount('linkedProjects'); }, 3); } }