Passed
Push — master ( ae0a03...686af4 )
by Magnar Ovedal
03:17
created

Length::getMax()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stadly\PasswordPolice\Rule;
6
7
use InvalidArgumentException;
8
use Stadly\PasswordPolice\Password;
9
use Stadly\PasswordPolice\Policy;
10
11
final class Length implements RuleInterface
12
{
13
    /**
14
     * @var int Minimum password length.
15
     */
16
    private $min;
17
18
    /**
19
     * @var int|null Maximum password length.
20
     */
21
    private $max;
22
23
    /**
24
     * @param int $min Minimum password length.
25
     * @param int|null $max Maximum password length.
26
     */
27 7
    public function __construct(int $min = 8, ?int $max = null)
28
    {
29 7
        if ($min < 0) {
30 1
            throw new InvalidArgumentException('Min cannot be negative.');
31
        }
32 6
        if ($max !== null && $max < $min) {
33 1
            throw new InvalidArgumentException('Max cannot be smaller than min.');
34
        }
35 5
        if ($min === 0 && $max === null) {
36 1
            throw new InvalidArgumentException('Min cannot be zero when max is unconstrained.');
37
        }
38
39 4
        $this->min = $min;
40 4
        $this->max = $max;
41 4
    }
42
43
    /**
44
     * @return int Minimum password length.
45
     */
46 1
    public function getMin(): int
47
    {
48 1
        return $this->min;
49
    }
50
51
    /**
52
     * @return int|null Maximum password length.
53
     */
54 1
    public function getMax(): ?int
55
    {
56 1
        return $this->max;
57
    }
58
59
    /**
60
     * Check whether a password is in compliance with the rule.
61
     *
62
     * @param Password|string $password Password to check.
63
     * @return bool Whether the password is in compliance with the rule.
64
     */
65 5
    public function test($password): bool
66
    {
67 5
        $count = $this->getNoncompliantCount((string)$password);
68
69 5
        return $count === null;
70
    }
71
72
    /**
73
     * Enforce that a password is in compliance with the rule.
74
     *
75
     * @param Password|string $password Password that must adhere to the rule.
76
     * @throws RuleException If the password does not adhrere to the rule.
77
     */
78 2
    public function enforce($password): void
79
    {
80 2
        $count = $this->getNoncompliantCount((string)$password);
81
82 2
        if ($count !== null) {
83 1
            throw new RuleException($this, $this->getMessage());
84
        }
85 1
    }
86
87
    /**
88
     * @param string $password Password to count characters in.
89
     * @return int Number of characters if not in compliance with the rule.
90
     */
91 7
    private function getNoncompliantCount(string $password): ?int
92
    {
93 7
        $count = $this->getCount($password);
94
95 7
        if ($count < $this->min) {
96 2
            return $count;
97
        }
98
99 5
        if (null !== $this->max && $this->max < $count) {
100 1
            return $count;
101
        }
102
103 4
        return null;
104
    }
105
106
    /**
107
     * @param string $password Password to count characters in.
108
     * @return int Number of characters.
109
     */
110 7
    private function getCount(string $password): int
111
    {
112 7
        return mb_strlen($password);
113
    }
114
115
    /**
116
     * {@inheritDoc}
117
     */
118 5
    public function getMessage(): string
119
    {
120 5
        $translator = Policy::getTranslator();
121
122 5
        if ($this->max === null) {
123 1
            return $translator->trans(
124
                'There must be at least one character.|'.
125 1
                'There must be at least %count% characters.',
126 1
                ['%count%' => $this->min]
127
            );
128
        }
129
130 4
        if ($this->max === 0) {
131 1
            return $translator->trans(
132 1
                'There must be no characters.'
133
            );
134
        }
135
136 3
        if ($this->min === 0) {
137 1
            return $translator->trans(
138
                'There must be at most one character.|'.
139 1
                'There must be at most %count% characters.',
140 1
                ['%count%' => $this->max]
141
            );
142
        }
143
144 2
        if ($this->min === $this->max) {
145 1
            return $translator->trans(
146
                'There must be exactly one character.|'.
147 1
                'There must be exactly %count% characters.',
148 1
                ['%count%' => $this->min]
149
            );
150
        }
151
152 1
        return $translator->trans(
153 1
            'There must be between %min% and %max% characters.',
154 1
            ['%min%' => $this->min, '%max%' => $this->max]
155
        );
156
    }
157
}
158