coolify/app/Livewire/Project/New/DockerCompose.php
Andras Bacsai 1da1f32f0e refactor: use forceCreate() for internal model creation
Replace create() with forceCreate() across internal model creation operations to bypass mass assignment protection. This is appropriate for internal code that constructs complete model state without user input.

Add InternalModelCreationMassAssignmentTest to ensure internal model creation behavior is properly tested. Optimize imports by using shortened Livewire attribute references and removing unused imports.
2026-03-30 13:04:11 +02:00

95 lines
3.5 KiB
PHP

<?php
namespace App\Livewire\Project\New;
use App\Models\EnvironmentVariable;
use App\Models\Project;
use App\Models\Service;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use Livewire\Component;
use Symfony\Component\Yaml\Yaml;
class DockerCompose extends Component
{
public string $dockerComposeRaw = '';
public string $envFile = '';
public array $parameters;
public array $query;
public function mount()
{
$this->parameters = get_route_parameters();
$this->query = request()->query();
if (isDev()) {
$this->dockerComposeRaw = file_get_contents(base_path('templates/test-database-detection.yaml'));
}
}
public function submit()
{
$server_id = $this->query['server_id'];
try {
$this->validate([
'dockerComposeRaw' => 'required',
]);
$this->dockerComposeRaw = Yaml::dump(Yaml::parse($this->dockerComposeRaw), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
// Validate for command injection BEFORE saving to database
validateDockerComposeForInjection($this->dockerComposeRaw);
$project = Project::ownedByCurrentTeam()->where('uuid', $this->parameters['project_uuid'])->firstOrFail();
$environment = $project->environments()->where('uuid', $this->parameters['environment_uuid'])->firstOrFail();
$destination_uuid = $this->query['destination'];
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
if (! $destination) {
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
}
if (! $destination) {
throw new \Exception('Destination not found. What?!');
}
$destination_class = $destination->getMorphClass();
$service = Service::forceCreate([
'docker_compose_raw' => $this->dockerComposeRaw,
'environment_id' => $environment->id,
'server_id' => (int) $server_id,
'destination_id' => $destination->id,
'destination_type' => $destination_class,
]);
$variables = parseEnvFormatToArray($this->envFile);
foreach ($variables as $key => $data) {
// Extract value and comment from parsed data
// Handle both array format ['value' => ..., 'comment' => ...] and plain string values
$value = is_array($data) ? ($data['value'] ?? '') : $data;
$comment = is_array($data) ? ($data['comment'] ?? null) : null;
EnvironmentVariable::create([
'key' => $key,
'value' => $value,
'comment' => $comment,
'is_preview' => false,
'resourceable_id' => $service->id,
'resourceable_type' => $service->getMorphClass(),
]);
}
$service->parse(isNew: true);
// Apply service-specific application prerequisites
applyServiceApplicationPrerequisites($service);
return redirect()->route('project.service.configuration', [
'service_uuid' => $service->uuid,
'environment_uuid' => $environment->uuid,
'project_uuid' => $project->uuid,
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}