Passed
Push — master ( 71a920...7ee81a )
by Magnar Ovedal
02:31
created

ChangeDate::test()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 6
ccs 4
cts 4
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 DateTimeInterface;
8
use StableSort\StableSort;
9
use Stadly\PasswordPolice\Constraint\Date;
10
use Carbon\CarbonInterval;
11
use Stadly\Date\Interval;
12
use Stadly\PasswordPolice\Password;
13
use Stadly\PasswordPolice\Policy;
14
use Stadly\PasswordPolice\Rule;
15
use Stadly\PasswordPolice\ValidationError;
16
17
final class ChangeDate implements Rule
18
{
19
    /**
20
     * @var Date[] Rule constraints.
21
     */
22
    private $constraints;
23
24
    /**
25
     * @param DateTimeInterface|null $min Minimum time for when the password was last changed.
26
     * @param DateTimeInterface|null $max Maximum time for when the password was last changed.
27
     * @param int $weight Constraint weight.
28
     */
29 6
    public function __construct(?DateTimeInterface $min, ?DateTimeInterface $max = null, int $weight = 1)
30
    {
31 6
        $this->addConstraint($min, $max, $weight);
32 5
    }
33
34
    /**
35
     * @param DateTimeInterface|null $min Minimum time for when the password was last changed.
36
     * @param DateTimeInterface|null $max Maximum time for when the password was last changed.
37
     * @param int $weight Constraint weight.
38
     * @return $this
39
     */
40 2
    public function addConstraint(?DateTimeInterface $min, ?DateTimeInterface $max = null, int $weight = 1): self
41
    {
42 2
        $this->constraints[] = new Date($min, $max, $weight);
43
44
        StableSort::usort($this->constraints, function (Date $a, Date $b): int {
45 2
            return $b->getWeight() <=> $a->getWeight();
46 2
        });
47
48 2
        return $this;
49
    }
50
51
    /**
52
     * Check whether a password is in compliance with the rule.
53
     *
54
     * @param Password|string $password Password to check.
55
     * @param int|null $weight Don't consider constraints with lower weights.
56
     * @return bool Whether the password is in compliance with the rule.
57
     */
58 6
    public function test($password, ?int $weight = 1): bool
59
    {
60 6
        $date = $this->getDate($password);
61 6
        $constraint = $this->getViolation($date, $weight);
62
63 6
        return $constraint === null;
64
    }
65
66
    /**
67
     * Validate that a password is in compliance with the rule.
68
     *
69
     * @param Password|string $password Password to validate.
70
     * @return ValidationError|null Validation error describing why the password is not in compliance with the rule.
71
     */
72 5
    public function validate($password): ?ValidationError
73
    {
74 5
        $date = $this->getDate($password);
75 5
        $constraint = $this->getViolation($date);
76
77 5
        if ($constraint !== null) {
78 4
            assert($date !== null);
79 4
            return new ValidationError(
80 4
                $this->getMessage($constraint, $date),
81 4
                $password,
82 4
                $this,
83 4
                $constraint->getWeight()
84
            );
85
        }
86
87 1
        return null;
88
    }
89
90
    /**
91
     * @param DateTimeInterface|null $date When the password was last changed.
92
     * @param int|null $weight Don't consider constraints with lower weights.
93
     * @return Date|null Constraint violated by the count.
94
     */
95 11
    private function getViolation(?DateTimeInterface $date, ?int $weight = null): ?Date
96
    {
97 11
        if ($date === null) {
98 1
            return null;
99
        }
100
101 10
        foreach ($this->constraints as $constraint) {
102 10
            if ($weight !== null && $constraint->getWeight() < $weight) {
103 1
                continue;
104
            }
105 9
            if (!$constraint->test($date)) {
106 9
                return $constraint;
107
            }
108
        }
109
110 4
        return null;
111
    }
112
113
    /**
114
     * @param Password|string $password Password to check when was last changed.
115
     * @return DateTimeInterface|null When the password was last changed.
116
     */
117 11
    private function getDate($password): ?DateTimeInterface
118
    {
119 11
        if ($password instanceof Password) {
120 10
            $formerPasswords = $password->getFormerPasswords();
121
122 10
            if ($formerPasswords !== []) {
123 10
                return reset($formerPasswords)->getDate();
124
            }
125
        }
126 1
        return null;
127
    }
128
129
    /**
130
     * @param Date $constraint Constraint that is violated.
131
     * @param DateTimeInterface $date Date that violates the constraint.
132
     * @return string Message explaining the violation.
133
     */
134 4
    private function getMessage(Date $constraint, DateTimeInterface $date): string
0 ignored issues
show
Unused Code introduced by
The parameter $date 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

134
    private function getMessage(Date $constraint, /** @scrutinizer ignore-unused */ DateTimeInterface $date): 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...
135
    {
136 4
        $translator = Policy::getTranslator();
137 4
        $minString = $constraint->getMin() === null ? '' : $constraint->getMin()->format('Y-m-d H:i:s');
138 4
        $maxString = $constraint->getMax() === null ? '' : $constraint->getMax()->format('Y-m-d H:i:s');
139
140 4
        if ($constraint->getMax() === null) {
141 1
            return $translator->trans(
142 1
                'The password must have been changed on or after %date%.',
143 1
                ['%date%' => $minString]
144
            );
145
        }
146
147 3
        if ($constraint->getMin() === null) {
148 1
            return $translator->trans(
149 1
                'The password must have been changed on or before %date%.',
150 1
                ['%date%' => $maxString]
151
            );
152
        }
153
154 2
        if ($constraint->getMin() == $constraint->getMax()) {
155 1
            return $translator->trans(
156 1
                'The password must have been changed at %date%.',
157 1
                ['%date%' => $minString]
158
            );
159
        }
160
161 1
        return $translator->trans(
162 1
            'The password must have been changed between %min% and %max%.',
163 1
            ['%min%' => $minString, '%max%' => $maxString]
164
        );
165
    }
166
}
167