Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BCrwHHnGCB5XH968Nxokqw
60 lines
2.0 KiB
PHP
60 lines
2.0 KiB
PHP
<?php
|
||
|
||
namespace App\Presenters;
|
||
|
||
use App\Enums\DueMode;
|
||
use App\Enums\EventState;
|
||
use App\Ingest\ManualEvents;
|
||
use App\Models\Event;
|
||
use App\Scheduling\DueResolver;
|
||
|
||
/** Единое представление события: для клиентов (/api), для пользователя (/me, инбокс, агент). */
|
||
final class EventPresenter
|
||
{
|
||
/** @return array<string,mixed> */
|
||
public static function forClient(Event $event): array
|
||
{
|
||
return [
|
||
'id' => $event->id,
|
||
'source_ref' => $event->source_ref,
|
||
'topic' => $event->topic,
|
||
'state' => $event->state->value,
|
||
'due_at' => self::dueAt($event),
|
||
'fire_at' => $event->fire_on->format('Y-m-d'),
|
||
'after_due' => $event->after_due->value,
|
||
'payload' => $event->payload,
|
||
'done_at' => $event->done_at?->toIso8601String(),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Пользователю (и агенту) поверх клиентского: чей источник и можно ли править.
|
||
* `editable` — явный флаг, а не «сравни source со строкой».
|
||
*
|
||
* @return array<string,mixed>
|
||
*/
|
||
public static function forUser(Event $event): array
|
||
{
|
||
return self::forClient($event) + [
|
||
'source' => $event->source->name,
|
||
'editable' => ManualEvents::owns($event),
|
||
];
|
||
}
|
||
|
||
/** Подпись закрытого события в архиве. */
|
||
public static function closedAs(Event $event): string
|
||
{
|
||
return $event->state === EventState::Expired ? 'Истекло' : ($event->payload['done_label'] ?? 'Сделано');
|
||
}
|
||
|
||
public static function dueAt(Event $event): string
|
||
{
|
||
if ($event->due_mode === DueMode::Fixed) {
|
||
return $event->due_instant->toIso8601String();
|
||
}
|
||
$date = $event->due_date->format('Y-m-d');
|
||
|
||
return $event->due_time === DueResolver::WHOLE_DAY ? $date : $date.'T'.substr($event->due_time, 0, 5);
|
||
}
|
||
}
|