Passed
Push — master ( 6842d1...dc0637 )
by Magnar Ovedal
02:18
created

Dictionary::__construct()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 3
nop 3
dl 0
loc 12
ccs 8
cts 8
cp 1
crap 4
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\Policy;
9
use Stadly\PasswordPolice\WordList\WordListInterface;
10
11
final class Dictionary implements RuleInterface
12
{
13
    /**
14
     * @var WordListInterface Word list for the dictionary.
15
     */
16
    private $wordList;
17
18
    /**
19
     * @var int Minimum word length.
20
     */
21
    private $min;
22
23
    /**
24
     * @var int|null Maximum word length.
25
     */
26
    private $max;
27
28
    /**
29
     * @param WordListInterface $wordList Word list for the dictionary.
30
     * @param int $min Minimum word length.
31
     * @param int|null $max Maximum word length.
32
     */
33 7
    public function __construct(WordListInterface $wordList, int $min = 3, ?int $max = 25)
34
    {
35 7
        if ($min < 1) {
36 2
            throw new InvalidArgumentException('Min must be positive.');
37
        }
38 5
        if ($max !== null && $max < $min) {
39 1
            throw new InvalidArgumentException('Max cannot be smaller than min.');
40
        }
41
42 4
        $this->wordList = $wordList;
43 4
        $this->min = $min;
44 4
        $this->max = $max;
45 4
    }
46
47
    /**
48
     * @return WordListInterface Word list for the dictionary.
49
     */
50 1
    public function getWordList(): WordListInterface
51
    {
52 1
        return $this->wordList;
53
    }
54
55
    /**
56
     * @return int Minimum word length.
57
     */
58 1
    public function getMin(): int
59
    {
60 1
        return $this->min;
61
    }
62
63
    /**
64
     * @return int|null Maximum word length.
65
     */
66 1
    public function getMax(): ?int
67
    {
68 1
        return $this->max;
69
    }
70
71
    /**
72
     * {@inheritDoc}
73
     */
74 7
    public function test(string $password): bool
75
    {
76 7
        for ($start = 0; $start < mb_strlen($password); ++$start) {
77 7
            $word = mb_substr($password, $start, $this->max);
78
79 7
            for ($wordLength = mb_strlen($word); $this->min <= $wordLength; --$wordLength) {
80 6
                $word = mb_substr($word, 0, $wordLength);
81
82 6
                if ($this->wordList->contains($word)) {
83 5
                    return false;
84
                }
85
            }
86
        }
87 2
        return true;
88
    }
89
90
    /**
91
     * {@inheritDoc}
92
     */
93 2
    public function enforce(string $password): void
94
    {
95 2
        if (!$this->test($password)) {
96 1
            throw new RuleException($this, $this->getMessage());
97
        }
98 1
    }
99
100
    /**
101
     * {@inheritDoc}
102
     */
103 1
    public function getMessage(): string
104
    {
105 1
        $translator = Policy::getTranslator();
106
107 1
        return $translator->trans(
108 1
            'Must not contain common dictionary words.'
109
        );
110
    }
111
}
112