Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
ComparisonOperator
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
6 / 6
39
100.00% covered (success)
100.00%
1 / 1
 description
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
9
 symbol
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
9
 isSetOperator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 compare
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
9
 negate
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
9
 candidateSet
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5/**
6 * Ergonomic utilities for PHP enums, including names, values, lookups, and option maps.
7 *
8 * This file is part of fast-forward/enum project.
9 *
10 * @author   Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
11 * @license  https://opensource.org/licenses/MIT MIT License
12 *
13 * @see      https://github.com/php-fast-forward/enum
14 * @see      https://github.com/php-fast-forward/enum/issues
15 * @see      https://php-fast-forward.github.io/enum/
16 * @see      https://datatracker.ietf.org/doc/html/rfc2119
17 */
18
19namespace FastForward\Enum\Comparison;
20
21use ValueError;
22use FastForward\Enum\DescribedEnumInterface;
23use FastForward\Enum\LabeledEnumInterface;
24use FastForward\Enum\Trait\Comparable;
25use FastForward\Enum\Trait\HasLabel;
26use FastForward\Enum\Trait\HasNameLookup;
27use FastForward\Enum\Trait\HasNameMap;
28use FastForward\Enum\Trait\HasNames;
29use FastForward\Enum\Trait\HasOptions;
30use FastForward\Enum\Trait\HasValueMap;
31use FastForward\Enum\Trait\HasValues;
32
33enum ComparisonOperator: string implements DescribedEnumInterface, LabeledEnumInterface
34{
35    use Comparable;
36    use HasLabel;
37    use HasNameLookup;
38    use HasNameMap;
39    use HasNames;
40    use HasOptions;
41    use HasValueMap;
42    use HasValues;
43
44    case Equal = 'eq';
45    case NotEqual = 'neq';
46    case GreaterThan = 'gt';
47    case GreaterThanOrEqual = 'gte';
48    case LessThan = 'lt';
49    case LessThanOrEqual = 'lte';
50    case In = 'in';
51    case NotIn = 'not_in';
52
53    /**
54     * @return string
55     */
56    public function description(): string
57    {
58        return match ($this) {
59            self::Equal => 'Matches when both operands are strictly equal.',
60            self::NotEqual => 'Matches when both operands are not strictly equal.',
61            self::GreaterThan => 'Matches when the left operand is greater than the right operand.',
62            self::GreaterThanOrEqual => 'Matches when the left operand is greater than or equal to the right operand.',
63            self::LessThan => 'Matches when the left operand is less than the right operand.',
64            self::LessThanOrEqual => 'Matches when the left operand is less than or equal to the right operand.',
65            self::In => 'Matches when the left operand is contained in the right-hand candidate set.',
66            self::NotIn => 'Matches when the left operand is not contained in the right-hand candidate set.',
67        };
68    }
69
70    /**
71     * @return string
72     */
73    public function symbol(): string
74    {
75        return match ($this) {
76            self::Equal => '=',
77            self::NotEqual => '!=',
78            self::GreaterThan => '>',
79            self::GreaterThanOrEqual => '>=',
80            self::LessThan => '<',
81            self::LessThanOrEqual => '<=',
82            self::In => 'IN',
83            self::NotIn => 'NOT IN',
84        };
85    }
86
87    /**
88     * @return bool
89     */
90    public function isSetOperator(): bool
91    {
92        return $this->in([self::In, self::NotIn]);
93    }
94
95    /**
96     * @param mixed $left
97     * @param mixed $right
98     *
99     * @return bool
100     */
101    public function compare(mixed $left, mixed $right): bool
102    {
103        return match ($this) {
104            self::Equal => $left === $right,
105            self::NotEqual => $left !== $right,
106            self::GreaterThan => $left > $right,
107            self::GreaterThanOrEqual => $left >= $right,
108            self::LessThan => $left < $right,
109            self::LessThanOrEqual => $left <= $right,
110            self::In => \in_array($left, $this->candidateSet($right), true),
111            self::NotIn => ! \in_array($left, $this->candidateSet($right), true),
112        };
113    }
114
115    /**
116     * @return self
117     */
118    public function negate(): self
119    {
120        return match ($this) {
121            self::Equal => self::NotEqual,
122            self::NotEqual => self::Equal,
123            self::GreaterThan => self::LessThanOrEqual,
124            self::GreaterThanOrEqual => self::LessThan,
125            self::LessThan => self::GreaterThanOrEqual,
126            self::LessThanOrEqual => self::GreaterThan,
127            self::In => self::NotIn,
128            self::NotIn => self::In,
129        };
130    }
131
132    /**
133     * @param mixed $right
134     *
135     * @return list<mixed>
136     */
137    private function candidateSet(mixed $right): array
138    {
139        if (! \is_array($right)) {
140            throw new ValueError(\sprintf('Comparison operator %s expects an array candidate set.', $this->name));
141        }
142
143        return array_values($right);
144    }
145}