refactor(scheduled-task): simplify server() with nullsafe operators and add return type

Replace nested null checks with nullsafe operator chains, add ?Server
return type, drop unreachable database branch, and cover all paths with
feature tests.
This commit is contained in:
Andras Bacsai 2026-05-04 12:26:15 +02:00
parent 8e22ce4ba7
commit 1849b5903e
2 changed files with 72 additions and 12 deletions

View file

@ -76,20 +76,14 @@ public function executions(): HasMany
return $this->hasMany(ScheduledTaskExecution::class)->orderBy('created_at', 'desc');
}
public function server()
public function server(): ?Server
{
if ($this->application) {
if ($this->application->destination && $this->application->destination->server) {
return $this->application->destination->server;
}
} elseif ($this->service) {
if ($this->service->destination && $this->service->destination->server) {
return $this->service->destination->server;
}
} elseif ($this->database) {
if ($this->database->destination && $this->database->destination->server) {
return $this->database->destination->server;
}
return $this->application->destination?->server;
}
if ($this->service) {
return $this->service->destination?->server;
}
return null;

View file

@ -0,0 +1,66 @@
<?php
use App\Models\Application;
use App\Models\Project;
use App\Models\ScheduledTask;
use App\Models\Server;
use App\Models\Service;
use App\Models\StandaloneDocker;
use App\Models\Team;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->team = Team::factory()->create();
$this->server = Server::factory()->create(['team_id' => $this->team->id]);
$this->destination = StandaloneDocker::where('server_id', $this->server->id)->first();
$this->project = Project::factory()->create(['team_id' => $this->team->id]);
$this->environment = $this->project->environments()->first();
});
it('returns null when neither application nor service is set', function () {
$task = ScheduledTask::factory()->create([
'team_id' => $this->team->id,
]);
expect($task->server())->toBeNull();
});
it('does not throw when accessing dynamic properties on a parentless task', function () {
$task = ScheduledTask::factory()->create([
'team_id' => $this->team->id,
]);
expect(fn () => $task->server())->not->toThrow(Exception::class);
});
it('resolves server via application destination', function () {
$application = Application::factory()->create([
'environment_id' => $this->environment->id,
'destination_id' => $this->destination->id,
'destination_type' => $this->destination->getMorphClass(),
]);
$task = ScheduledTask::factory()->create([
'application_id' => $application->id,
'team_id' => $this->team->id,
]);
expect($task->server()?->id)->toBe($this->server->id);
});
it('resolves server via service destination', function () {
$service = Service::factory()->create([
'environment_id' => $this->environment->id,
'destination_id' => $this->destination->id,
'destination_type' => $this->destination->getMorphClass(),
]);
$task = ScheduledTask::factory()->create([
'service_id' => $service->id,
'team_id' => $this->team->id,
]);
expect($task->server()?->id)->toBe($this->server->id);
});