LengthRule::getMessage()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 35
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 21
c 1
b 0
f 0
nc 5
nop 3
dl 0
loc 35
ccs 19
cts 19
cp 1
crap 5
rs 9.2728
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stadly\PasswordPolice\Rule;
6
7
use StableSort\StableSort;
8
use Stadly\PasswordPolice\Constraint\CountConstraint;
9
use Stadly\PasswordPolice\Password;
10
use Stadly\PasswordPolice\Rule;
11
use Stadly\PasswordPolice\ValidationError;
12
use Symfony\Contracts\Translation\LocaleAwareInterface;
13
use Symfony\Contracts\Translation\TranslatorInterface;
14
15
final class LengthRule implements Rule
16
{
17
    /**
18
     * @var array<CountConstraint> Rule constraints.
19
     */
20
    private $constraints = [];
21
22
    /**
23
     * @param int $min Minimum password length.
24
     * @param int|null $max Maximum password length.
25
     * @param int $weight Constraint weight.
26
     */
27 15
    public function __construct(int $min = 8, ?int $max = null, int $weight = 1)
28
    {
29 15
        $this->addConstraint($min, $max, $weight);
30 13
    }
31
32
    /**
33
     * @param int $min Minimum password length.
34
     * @param int|null $max Maximum password length.
35
     * @param int $weight Constraint weight.
36
     * @return $this
37
     */
38 1
    public function addConstraint(int $min = 8, ?int $max = null, int $weight = 1): self
39
    {
40 1
        $this->constraints[] = new CountConstraint($min, $max, $weight);
41
42
        StableSort::usort($this->constraints, static function (CountConstraint $a, CountConstraint $b): int {
43 1
            return $b->getWeight() <=> $a->getWeight();
44 1
        });
45
46 1
        return $this;
47
    }
48
49
    /**
50
     * Check whether a password is in compliance with the rule.
51
     *
52
     * @param Password|string $password Password to check.
53
     * @param int|null $weight Don't consider constraints with lower weights.
54
     * @return bool Whether the password is in compliance with the rule.
55
     */
56 6
    public function test($password, ?int $weight = null): bool
57
    {
58 6
        $count = $this->getCount((string)$password);
59 6
        $constraint = $this->getViolation($count, $weight);
60
61 6
        return $constraint === null;
62
    }
63
64
    /**
65
     * Validate that a password is in compliance with the rule.
66
     *
67
     * @param Password|string $password Password to validate.
68
     * @param TranslatorInterface&LocaleAwareInterface $translator Translator for translating messages.
69
     * @return ValidationError|null Validation error describing why the password is not in compliance with the rule.
70
     */
71 6
    public function validate($password, TranslatorInterface $translator): ?ValidationError
72
    {
73 6
        $count = $this->getCount((string)$password);
74 6
        $constraint = $this->getViolation($count);
75
76 6
        if ($constraint !== null) {
77 5
            return new ValidationError(
78 5
                $this->getMessage($constraint, $count, $translator),
79 5
                $password,
80 5
                $this,
81 5
                $constraint->getWeight()
82
            );
83
        }
84
85 1
        return null;
86
    }
87
88
    /**
89
     * @param int $count Number of characters.
90
     * @param int|null $weight Don't consider constraints with lower weights.
91
     * @return CountConstraint|null Constraint violated by the count.
92
     */
93 12
    private function getViolation(int $count, ?int $weight = null): ?CountConstraint
94
    {
95 12
        foreach ($this->constraints as $constraint) {
96 12
            if ($weight !== null && $constraint->getWeight() < $weight) {
97 1
                continue;
98
            }
99 11
            if (!$constraint->test($count)) {
100 11
                return $constraint;
101
            }
102
        }
103
104 5
        return null;
105
    }
106
107
    /**
108
     * @param string $password Password to count characters in.
109
     * @return int Number of characters.
110
     */
111 12
    private function getCount(string $password): int
112
    {
113 12
        return mb_strlen($password);
114
    }
115
116
    /**
117
     * @param CountConstraint $constraint Constraint that is violated.
118
     * @param int $count Count that violates the constraint.
119
     * @param TranslatorInterface&LocaleAwareInterface $translator Translator for translating messages.
120
     * @return string Message explaining the violation.
121
     */
122 5
    private function getMessage(CountConstraint $constraint, int $count, TranslatorInterface $translator): string
0 ignored issues
show
Unused Code introduced by
The parameter $count is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

122
    private function getMessage(CountConstraint $constraint, /** @scrutinizer ignore-unused */ int $count, TranslatorInterface $translator): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
123
    {
124 5
        if ($constraint->getMax() === null) {
125 1
            return $translator->trans(
126
                'The password must contain at least one character.|' .
127 1
                'The password must contain at least %count% characters.',
128 1
                ['%count%' => $constraint->getMin()]
129
            );
130
        }
131
132 4
        if ($constraint->getMax() === 0) {
133 1
            return $translator->trans(
134 1
                'The password cannot contain characters.'
135
            );
136
        }
137
138 3
        if ($constraint->getMin() === 0) {
139 1
            return $translator->trans(
140
                'The password must contain at most one character.|' .
141 1
                'The password must contain at most %count% characters.',
142 1
                ['%count%' => $constraint->getMax()]
143
            );
144
        }
145
146 2
        if ($constraint->getMin() === $constraint->getMax()) {
147 1
            return $translator->trans(
148
                'The password must contain exactly one character.|' .
149 1
                'The password must contain exactly %count% characters.',
150 1
                ['%count%' => $constraint->getMin()]
151
            );
152
        }
153
154 1
        return $translator->trans(
155 1
            'The password must contain between %min% and %max% characters.',
156 1
            ['%min%' => $constraint->getMin(), '%max%' => $constraint->getMax()]
157
        );
158
    }
159
}
160