|null $areas * @return array|null */ public function handle(Project $project, ?array $areas = null): ?array { $project->loadMissing('projectTemplate'); /** @var ProjectTemplate|null $projectTemplate */ $projectTemplate = $project->projectTemplate; if ($projectTemplate === null) { return null; } $selectedAreas = $areas === null ? DuplicateProjectConfiguration::copyableAreas() : $this->duplicateProjectConfiguration->normalizeCopyAreas($areas); $normalizedTemplateConfiguration = $this->duplicateProjectConfiguration->normalizeConfiguration( $projectTemplate->configuration_snapshot ?? [], ); $templateConfiguration = collect($normalizedTemplateConfiguration) ->only($selectedAreas) ->all(); $currentConfiguration = $this->duplicateProjectConfiguration->export($project, $selectedAreas); $persistedOverrides = $projectTemplate->is_published ? array_values(array_intersect($project->template_overrides ?? [], $selectedAreas)) : []; $overriddenAreas = []; $inheritedAreas = []; foreach ($selectedAreas as $area) { $label = $this->labelForArea($area); $hasTemplateValue = array_key_exists($area, $templateConfiguration); if (! $hasTemplateValue) { continue; } if (! in_array($area, $persistedOverrides, true)) { $inheritedAreas[] = [ 'label' => $label, 'value' => $area, ]; continue; } $overriddenAreas[] = [ 'label' => $label, 'value' => $area, ]; } $overriddenAreaValues = array_flip(array_column($overriddenAreas, 'value')); $inheritedAreaValues = array_flip(array_column($inheritedAreas, 'value')); return [ 'effectiveConfiguration' => array_replace($templateConfiguration, array_intersect_key($currentConfiguration, $overriddenAreaValues)), 'inheritedAreas' => $inheritedAreas, 'inheritedConfiguration' => array_intersect_key($templateConfiguration, $inheritedAreaValues), 'inheritsFromTemplate' => $projectTemplate->is_published, 'overriddenAreas' => $overriddenAreas, 'overriddenConfiguration' => array_intersect_key($currentConfiguration, $overriddenAreaValues), 'resetRequirements' => $this->resetRequirements($project, $templateConfiguration, $persistedOverrides), 'templateConfiguration' => $templateConfiguration, 'templateId' => $projectTemplate->id, 'templateName' => $projectTemplate->name, 'templateSlug' => $projectTemplate->slug, ]; } /** * @param array $templateConfiguration * @param list $persistedOverrides * @return array */ private function resetRequirements(Project $project, array $templateConfiguration, array $persistedOverrides): array { if (! in_array(DuplicateProjectConfiguration::COPY_TICKET_STATUSES, $persistedOverrides, true)) { return []; } $templateStatuses = $templateConfiguration[DuplicateProjectConfiguration::COPY_TICKET_STATUSES] ?? []; if (! is_array($templateStatuses)) { return []; } $statuses = $project->ticketStatuses()->withCount('tickets')->get()->values(); $replacementOptions = $statuses->take(count($templateStatuses))->map( static fn ($status): array => ['id' => $status->id, 'name' => $status->name], )->all(); $removedStatuses = $statuses->slice(count($templateStatuses)) ->filter(static fn ($status): bool => $status->tickets_count > 0) ->map(static fn ($status): array => [ 'id' => $status->id, 'name' => $status->name, 'ticketCount' => $status->tickets_count, ]) ->values() ->all(); return $removedStatuses === [] ? [] : [ DuplicateProjectConfiguration::COPY_TICKET_STATUSES => [ 'removedStatuses' => $removedStatuses, 'replacementOptions' => $replacementOptions, ], ]; } private function labelForArea(string $area): string { foreach (DuplicateProjectConfiguration::copyAreaOptions() as $option) { if ($option['value'] === $area) { return $option['label']; } } return $area; } }