Lines 100.00% 13 / 13
Methods 100.00% 5 / 5
Classes 100.00% 1 / 1
Covered by tests of size
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 isVisible 100.00% 1 / 1 100.00% 1 / 1 3
 isPermitted 100.00% 4 / 4 100.00% 1 / 1 2
 isActivated 100.00% 1 / 1 100.00% 1 / 1 1
 isWithinPublicationWindow 100.00% 6 / 6 100.00% 1 / 1 4
33final readonly class RecordVisibility
34{
35    /**
36     * The solution ID Faq::getFaq() stamps on its placeholder for records that do not
37     * exist or that the requester has no permission for.
38     */
39    private const int ACCESS_DENIED_SOLUTION_ID = 42;
40
41    /**
42     * @param array<string, mixed> $faqRecord a record as populated by Faq::getFaq()
43     */
44    public function __construct(
45        private array $faqRecord,
46    ) {
47    }
48
49    public function isVisible(): bool
50    {
51        return $this->isPermitted() && $this->isActivated() && $this->isWithinPublicationWindow();
52    }
53
54    /**
55     * An empty record means getFaq() was never called; treat that as denied so a missing
56     * load cannot be mistaken for a visible record.
57     */
58    private function isPermitted(): bool
59    {
60        if ($this->faqRecord === []) {
61            return false;
62        }
63
64        $solutionId = (int) ($this->faqRecord['solution_id'] ?? self::ACCESS_DENIED_SOLUTION_ID);
65
66        return self::ACCESS_DENIED_SOLUTION_ID !== $solutionId;
67    }
68
69    private function isActivated(): bool
70    {
71        return 'yes' === ($this->faqRecord['active'] ?? 'no');
72    }
73
74    private function isWithinPublicationWindow(): bool
75    {
76        $now = date(format: 'YmdHis');
77        $dateStart = (string) ($this->faqRecord['dateStart'] ?? '');
78        $dateEnd = (string) ($this->faqRecord['dateEnd'] ?? '');
79
80        $hasStarted = $dateStart === '' || $now >= $dateStart;
81        $hasNotEnded = $dateEnd === '' || $now <= $dateEnd;
82
83        return $hasStarted && $hasNotEnded;
84    }
85}