Lines 79.31% 46 / 58
Methods 83.33% 5 / 6
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 provide 100.00% 8 / 8 100.00% 1 / 1 4
 item 100.00% 19 / 19 100.00% 1 / 1 8
 doneBanners 0.00% 0 / 12 0.00% 0 / 1 2
 agent 100.00% 12 / 12 100.00% 1 / 1 1
 row 100.00% 6 / 6 100.00% 1 / 1 1
30final readonly class AgentProvider implements ProviderInterface
31{
32    public function __construct(
33        private UserRepository $userRepository,
34        private AgentStatRepository $agentStatRepository,
35        private TimelineEventRepository $timelineEventRepository,
36        private DoneBannerRepository $doneBannerRepository,
37    ) {
38    }
39
40    /**
41     * @return list<Agent>|Agent|null
42     */
43    public function provide(Operation $operation, array $uriVariables = [], array $context = []): array|Agent|null
44    {
45        if ($operation instanceof CollectionOperationInterface) {
46            $users = $this->userRepository->findVisibleAgents();
47            $latest = $this->agentStatRepository->findLatestByOwners($users);
48
49            return \array_values(\array_map(fn (User $user): Agent => $this->agent($user, $latest[(int) $user->id] ?? null), $users));
50        }
51
52        $user = $this->userRepository->findOneByAgentName((string) ($uriVariables['agentName'] ?? ''));
53        if (!$user instanceof User || !$user->isVisible(ProfilePart::AGENT)) {
54            return null;
55        }
56
57        return $this->item($user);
58    }
59
60    /** An agent with the parts they show. */
61    private function item(User $user): Agent
62    {
63        $stats = $this->agentStatRepository->findByOwner($user);
64        $showHistory = $user->isVisible(ProfilePart::STATS_HISTORY);
65
66        return $this->agent(
67            $user,
68            $stats[0] ?? null,
69            $user->isVisible(ProfilePart::LATEST_STATS) && isset($stats[0]) ? $this->row($stats[0]) : null,
70            $showHistory ? \array_map($this->row(...), $stats) : null,
71            $showHistory ? \array_map(
72                static fn (TimelineEvent $event): array => [
73                    'date' => $event->date?->format(TimelineEvent::DATE_FORMAT) ?? '',
74                    'endDate' => $event->endDate?->format(TimelineEvent::DATE_FORMAT),
75                    'text' => $event->text,
76                ],
77                $this->timelineEventRepository->findByOwner($user),
78            ) : null,
79            $user->isVisible(ProfilePart::CUSTOM_MEDALS) ? CustomMedals::fromArray($user->getCustomMedals()) : null,
80            $user->isVisible(ProfilePart::BANNERGRESS) ? Bannergress::fromStored($user->getBannergress()) : null,
81            $user->isVisible(ProfilePart::BANNERGRESS) ? $this->doneBanners($user) : null,
82        );
83    }
84
85    /**
86     * @return list<array{bannerId: string, title: string, missions: int, picture: string|null, startLatitude: float|null, startLongitude: float|null, doneAt: string|null}>
87     */
88    private function doneBanners(User $user): array
89    {
90        return \array_map(
91            static fn (DoneBanner $banner): array => [
92                'bannerId' => $banner->bannerId,
93                'title' => $banner->title,
94                'missions' => $banner->missions,
95                'picture' => $banner->picture,
96                'startLatitude' => $banner->startLatitude,
97                'startLongitude' => $banner->startLongitude,
98                'doneAt' => $banner->doneAt?->format(TimelineEvent::DATE_FORMAT),
99            ],
100            $this->doneBannerRepository->findByOwner($user),
101        );
102    }
103
104    /**
105     * @param array<string, int|string|null>|null                                                                                                                                $latestStats
106     * @param list<array<string, int|string|null>>|null                                                                                                                          $history
107     * @param list<array{date: string, endDate: string|null, text: string}>|null                                                                                                 $events
108     * @param list<array{bannerId: string, title: string, missions: int, picture: string|null, startLatitude: float|null, startLongitude: float|null, doneAt: string|null}>|null $doneBanners
109     */
110    private function agent(User $user, ?AgentStat $latest, ?array $latestStats = null, ?array $history = null, ?array $events = null, ?CustomMedals $customMedals = null, ?Bannergress $bannergress = null, ?array $doneBanners = null): Agent
111    {
112        return new Agent(
113            (string) $user->getAgentName(),
114            $latest?->faction,
115            $latest?->level,
116            $user->getVisibleAvatar(),
117            $latestStats,
118            $history,
119            $events,
120            $customMedals,
121            $bannergress,
122            $doneBanners,
123        );
124    }
125
126    /**
127     * A stats row as /api/agent-stats has it, without the id (that is the owner's only).
128     *
129     * @return array<string, int|string|null>
130     */
131    private function row(AgentStat $stat): array
132    {
133        return [
134            'datetime' => $stat->datetime->format(AgentStatInput::DATETIME_FORMAT),
135            'nickname' => $stat->nickname,
136            'faction' => $stat->faction,
137            ...$stat->getStats(),
138        ];
139    }
140}