48 lines
1.7 KiB
PHP
48 lines
1.7 KiB
PHP
<?php
|
|||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace App\Domain\Jobcard;
|
||
|
|
|
||
|
|
require_once __DIR__ . '/TimeCalculator.php';
|
||
|
|
|
||
|
|
final class TimeEntryValidator
|
||
|
|
{
|
||
|
|
public function validate(array $entry): array
|
||
|
|
{
|
||
|
|
$errors = [];
|
||
|
|
$date = trim((string)($entry['work_date'] ?? ''));
|
||
|
|
if (!$this->validDate($date)) $errors['work_date'] = 'Work date must be a valid date.';
|
||
|
|
|
||
|
|
$manual = null;
|
||
|
|
if (array_key_exists('hours', $entry) && $entry['hours'] !== null) {
|
||
|
|
if (!is_numeric($entry['hours'])) {
|
||
|
|
$errors['hours'] = 'Hours must be numeric.';
|
||
|
|
} else {
|
||
|
|
$manual = (float) $entry['hours'];
|
||
|
|
if ($manual < 0) $errors['hours'] = 'Hours must not be negative.';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
$start = $entry['start_time'] ?? null;
|
||
|
|
$end = $entry['end_time'] ?? null;
|
||
|
|
if ($manual === null && (($start === null) xor ($end === null))) {
|
||
|
|
$errors['time'] = 'Start and end time must be supplied together.';
|
||
|
|
}
|
||
|
|
$hours = \calculate_duration_hours($start !== null ? (string)$start : null, $end !== null ? (string)$end : null, $manual);
|
||
|
|
if ($hours === null && !isset($errors['hours']) && !isset($errors['time'])) {
|
||
|
|
$errors['time'] = 'A positive duration or manual hours is required.';
|
||
|
|
}
|
||
|
|
return ['valid' => $errors === [], 'hours' => $hours, 'errors' => $errors];
|
||
|
|
}
|
||
|
|
|
||
|
|
public function isValid(array $entry): bool
|
||
|
|
{
|
||
|
|
return $this->validate($entry)['valid'];
|
||
|
|
}
|
||
|
|
|
||
|
|
private function validDate(string $date): bool
|
||
|
|
{
|
||
|
|
$parsed = \DateTimeImmutable::createFromFormat('!Y-m-d', $date);
|
||
|
|
return $parsed !== false && $parsed->format('Y-m-d') === $date;
|
||
|
|
}
|
||
|
|
}
|