$selection * @param array $catalog * @return array */ public function describeSelection(HostingProduct $product, array $selection, array $catalog): array { $license = $this->findOption((array) ($catalog['licenses'] ?? []), (string) ($selection['license'] ?? '')); $image = $this->findOption((array) ($catalog['images'] ?? []), (string) ($selection['image'] ?? '')); $licenseLabel = (string) ($license['label'] ?? 'Remote Login Only'); $panel = (string) ($license['panel'] ?? ''); $vendorLicense = (string) ($license['license'] ?? ''); $osFamily = strtolower((string) ($image['os_family'] ?? 'linux')); $installLater = (bool) ($image['is_install_later'] ?? false); $supportedManagedImage = $this->supportedManagedImage($image); $linuxManagedCandidate = $panel === 'ladill' && ! $installLater && ! str_starts_with($osFamily, 'win') && $supportedManagedImage !== null; $supportedManagedImageLabels = array_values(array_filter(array_map( static fn (array $supported): string => (string) ($supported['label'] ?? ''), (array) config('hosting.server_order.managed_stack_supported_images', []) ))); if ($panel === 'ladill') { return [ 'mode' => 'server_manager', 'label' => $licenseLabel, 'runtime' => 'provider_api', 'is_ladill' => true, 'managed_stack_candidate' => $linuxManagedCandidate, 'managed_stack_supported_image' => $supportedManagedImage, 'managed_stack_supported_image_labels' => $supportedManagedImageLabels, 'hosting_panel_ready' => $linuxManagedCandidate, 'future_hosting_panel_status' => $linuxManagedCandidate ? 'managed_stack_supported' : 'not_available', 'current_capabilities' => [ 'Power controls', 'Status sync', 'Instance details', 'SSH access', ], 'future_capabilities' => $linuxManagedCandidate ? self::FUTURE_HOSTING_PANEL_CAPABILITIES : [], 'primary_message' => $linuxManagedCandidate ? 'Ladill Server Manager will provision this server with Ladill-managed controls on the selected supported Linux image.' : 'Ladill Server Manager is not available for the selected image.', 'secondary_message' => $linuxManagedCandidate ? 'After provisioning finishes, Server Manager can handle power, status, files, databases, domains, PHP, SSL, cron, and logs.' : 'Choose a plain supported Linux image without cPanel or Plesk. Supported Ladill-managed images: '.implode(', ', $supportedManagedImageLabels).'.', 'manager_cta_label' => 'Open Server Manager', 'hosting_panel_target_label' => 'Ladill Hosting Panel', 'product_type' => $product->type, ]; } if ($vendorLicense !== '') { return [ 'mode' => 'vendor_panel', 'label' => $licenseLabel, 'runtime' => 'in_server_panel', 'is_ladill' => false, 'managed_stack_candidate' => false, 'hosting_panel_ready' => false, 'future_hosting_panel_status' => 'external_panel', 'current_capabilities' => [ 'Provider provisioning', 'Server login', 'Installed panel management', ], 'future_capabilities' => [], 'primary_message' => "{$licenseLabel} will be the panel running inside this server. Ladill will not replace it with the shared hosting panel.", 'secondary_message' => 'Use Ladill for order tracking and server lifecycle, then manage sites and services from the installed panel itself.', 'manager_cta_label' => 'Open Panel', 'hosting_panel_target_label' => 'Ladill Hosting Panel', 'product_type' => $product->type, ]; } return [ 'mode' => 'remote_login_only', 'label' => $licenseLabel, 'runtime' => 'ssh_only', 'is_ladill' => false, 'managed_stack_candidate' => false, 'hosting_panel_ready' => false, 'future_hosting_panel_status' => 'not_enabled', 'current_capabilities' => [ 'Server login', ], 'future_capabilities' => [], 'primary_message' => 'This server will be provisioned without a Ladill-managed or commercial control panel.', 'secondary_message' => 'You will manage the machine directly over SSH or RDP until a panel or managed stack is installed separately.', 'manager_cta_label' => 'Open Access Details', 'hosting_panel_target_label' => 'Ladill Hosting Panel', 'product_type' => $product->type, ]; } /** * @param array> $options * @return array|null */ private function findOption(array $options, string $value): ?array { foreach ($options as $option) { if ((string) ($option['value'] ?? '') === $value) { return $option; } } return null; } /** * @param array|null $image * @return array|null */ private function supportedManagedImage(?array $image): ?array { if ($image === null) { return null; } $value = Str::lower((string) ($image['value'] ?? '')); $label = Str::lower((string) ($image['label'] ?? '')); $osFamily = Str::lower((string) ($image['os_family'] ?? '')); if ($this->imageIncludesVendorPanel($label)) { return null; } foreach ((array) config('hosting.server_order.managed_stack_supported_images', []) as $supported) { if (($supported['os_family'] ?? 'linux') !== '' && Str::lower((string) ($supported['os_family'] ?? 'linux')) !== $osFamily) { continue; } $supportedValue = Str::lower((string) ($supported['value'] ?? '')); if ($supportedValue !== '' && $supportedValue === $value) { return $supported; } foreach ((array) ($supported['match'] ?? []) as $needle) { if ($needle !== '' && Str::contains($label, Str::lower((string) $needle))) { return $supported; } } } return null; } private function imageIncludesVendorPanel(string $label): bool { foreach (['cpanel', 'plesk', 'whm'] as $needle) { if ($needle !== '' && Str::contains($label, $needle)) { return true; } } return false; } }