Lines
100.00%
14 / 14
Functions and Methods
100.00%
7 / 7
Classes and Traits
100.00%
1 / 1
| Name | Lines | Functions and Methods | CRAP | Classes and Traits | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| TimelineEntry | 100.00% | 14 / 14 | 100.00% | 7 / 7 | 15 | 100.00% | 1 / 1 | |||
| __construct | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| kind | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 5 | |||||
| counts | 100.00% | 4 / 4 | 100.00% | 1 / 1 | 1 | |||||
| days | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 1 | |||||
| withInTravel | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| isMilestone | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 2 | |||||
| isListed | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 4 | |||||
| 1 | <?php | |
| 2 | ||
| 3 | declare(strict_types=1); | |
| 4 | ||
| 5 | namespace App\Timeline; | |
| 6 | ||
| 7 | use App\Entity\AgentStat; | |
| 8 | use App\Entity\DoneBanner; | |
| 9 | use App\Entity\TimelineEvent; | |
| 10 | use App\Medal\MedalLevel; | |
| 11 | ||
| 12 | /** | |
| 13 | * One entry of the timeline: a stats upload with what changed since the one before it, a | |
| 14 | * custom event or a Bannergress banner done. A travel (an event with an end date) is two entries, | |
| 15 | * its end and its start (travelEdge); the entries between are in it (inTravel), with a line beside | |
| 16 | * the timeline. Travels cannot overlap. | |
| 17 | */ | |
| 18 | final readonly class TimelineEntry | |
| 19 | { | |
| 20 | public const string UPLOAD = 'upload'; | |
| 21 | ||
| 22 | public const string EVENT = 'event'; | |
| 23 | ||
| 24 | public const string TRAVEL = 'travel'; | |
| 25 | ||
| 26 | public const string BANNER = 'banner'; | |
| 27 | ||
| 28 | public const string TRAVEL_START = 'start'; | |
| 29 | ||
| 30 | public const string TRAVEL_END = 'end'; | |
| 31 | ||
| 32 | /** | |
| 33 | * @param list<MedalLevel> $medalUps medals with a higher level than in the previous upload, at their new level | |
| 34 | */ | |
| 35 | public function __construct( | |
| 36 | public \DateTimeImmutable $date, | |
| 37 | public ?AgentStat $stat = null, | |
| 38 | public ?TimelineEvent $event = null, | |
| 39 | /** A Bannergress banner done that day. */ | |
| 40 | public ?DoneBanner $banner = null, | |
| 41 | /** The first upload: nothing to compare with. */ | |
| 42 | public bool $first = false, | |
| 43 | public int $apGain = 0, | |
| 44 | /** The level, when it changed. */ | |
| 45 | public ?int $newLevel = null, | |
| 46 | public array $medalUps = [], | |
| 47 | /** The recursions, when there is a new one. */ | |
| 48 | public ?int $recursions = null, | |
| 49 | /** For a travel: TRAVEL_START or TRAVEL_END, the entry of that day. */ | |
| 50 | public ?string $travelEdge = null, | |
| 51 | /** Between the end and the start of a travel. */ | |
| 52 | public bool $inTravel = false, | |
| 53 | ) { | |
| 54 | } | |
| 55 | ||
| 56 | /** UPLOAD, EVENT, TRAVEL (an event with an end date) or BANNER: the timeline's filter. */ | |
| 57 | public function kind(): string | |
| 58 | { | |
| 59 | return match (true) { | |
| 60 | $this->banner instanceof DoneBanner => self::BANNER, | |
| 61 | !$this->event instanceof TimelineEvent => self::UPLOAD, | |
| 62 | $this->event->endDate instanceof \DateTimeImmutable => self::TRAVEL, | |
| 63 | default => self::EVENT, | |
| 64 | }; | |
| 65 | } | |
| 66 | ||
| 67 | /** | |
| 68 | * The number of entries of each kind, for the timeline's summary: a travel once, not its end | |
| 69 | * and its start (the app's `TimelineSummary`). | |
| 70 | * | |
| 71 | * @param list<self> $entries | |
| 72 | * | |
| 73 | * @return array<string, int> by kind | |
| 74 | */ | |
| 75 | public static function counts(array $entries): array | |
| 76 | { | |
| 77 | return \array_count_values(\array_map( | |
| 78 | static fn (self $entry): string => $entry->kind(), | |
| 79 | \array_filter($entries, static fn (self $entry): bool => self::TRAVEL_END !== $entry->travelEdge), | |
| 80 | )); | |
| 81 | } | |
| 82 | ||
| 83 | /** | |
| 84 | * The first and the last day it covers (Y-m-d), for the filter: an end or a start of a | |
| 85 | * travel its day. | |
| 86 | * | |
| 87 | * @return array{string, string} | |
| 88 | */ | |
| 89 | public function days(): array | |
| 90 | { | |
| 91 | $day = $this->date->format('Y-m-d'); | |
| 92 | ||
| 93 | return [$day, $day]; | |
| 94 | } | |
| 95 | ||
| 96 | /** The other entries in a travel (inTravel) with a new one: the timeline's travel line. */ | |
| 97 | public function withInTravel(): self | |
| 98 | { | |
| 99 | return new self($this->date, $this->stat, $this->event, $this->banner, $this->first, $this->apGain, $this->newLevel, $this->medalUps, $this->recursions, $this->travelEdge, true); | |
| 100 | } | |
| 101 | ||
| 102 | /** The first upload or a recursion: an upload the list always has (the app's `isMilestone`). */ | |
| 103 | public function isMilestone(): bool | |
| 104 | { | |
| 105 | return $this->first || null !== $this->recursions; | |
| 106 | } | |
| 107 | ||
| 108 | /** | |
| 109 | * Whether the list has it: an upload only for what changed besides the AP (a milestone, a new | |
| 110 | * level or medals at a higher tier), as the app's list. | |
| 111 | */ | |
| 112 | public function isListed(): bool | |
| 113 | { | |
| 114 | return self::UPLOAD !== $this->kind() || $this->isMilestone() || null !== $this->newLevel || [] !== $this->medalUps; | |
| 115 | } | |
| 116 | } |