PasswordHintService::checkMin()   A
last analyzed

Complexity

Conditions 4
Paths 5

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 5
nop 2
dl 0
loc 14
ccs 9
cts 9
cp 1
crap 4
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the login-cidadao project or it's bundles.
4
 *
5
 * (c) Guilherme Donato <guilhermednt on github>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace LoginCidadao\CoreBundle\Service;
12
13
use Rollerworks\Component\PasswordStrength\Validator\Constraints\PasswordRequirements;
14
use Symfony\Component\Translation\TranslatorInterface;
15
use Symfony\Component\Validator\Constraint;
16
use Symfony\Component\Validator\Mapping\ClassMetadataInterface;
17
use Symfony\Component\Validator\Validator\ValidatorInterface;
18
19
class PasswordHintService
20
{
21
    const TRANS_TYPE_RANGE = 'range';
22
    const TRANS_TYPE_MIN = 'min';
23
    const TRANS_TYPE_MAX = 'max';
24
    const TRANS_TYPE_NO_LIMIT = 'no_limit';
25
    const TRANS_WITH_REQS = 'with_reqs';
26
    const TRANS_NO_REQS = 'no_reqs';
27
28
    /** @var ValidatorInterface */
29
    private $validator;
30
31
    /** @var TranslatorInterface */
32
    private $translator;
33
34
    /** @var string */
35
    private $userClass;
36
37
    /**
38
     * PasswordHintService constructor.
39
     * @param ValidatorInterface $validator
40
     * @param TranslatorInterface $translator
41
     * @param string $userClass
42
     */
43 9
    public function __construct(ValidatorInterface $validator, TranslatorInterface $translator, $userClass)
44
    {
45 9
        $this->validator = $validator;
46 9
        $this->translator = $translator;
47 9
        $this->userClass = $userClass;
48 9
    }
49
50 5
    public function getPasswordRequirements()
51
    {
52
        $requirements = [
53 5
            'min' => 0,
54
            'max' => null,
55
            'requireLetters' => false,
56
            'requireNumbers' => false,
57
            'requireSpecialCharacter' => false,
58
        ];
59
60 5
        $metadata = $this->validator->getMetadataFor($this->userClass);
61
62 5
        if (!$metadata instanceof ClassMetadataInterface || false === $metadata->hasPropertyMetadata('plainPassword')) {
63 3
            return $requirements;
64
        }
65 2
        $propertyMetadata = $metadata->getPropertyMetadata('plainPassword');
66 2
        $constraints = [];
67 2
        foreach ($propertyMetadata as $pMetadata) {
68 2
            if (method_exists($pMetadata, 'getConstraints')) {
69 2
                $constraints = array_merge($constraints, $pMetadata->getConstraints());
70
            }
71
        }
72
73 2
        foreach ($constraints as $constraint) {
74 2
            $requirements = $this->checkMin($constraint, $requirements);
75 2
            $requirements = $this->checkMax($constraint, $requirements);
76 2
            $requirements = $this->checkCharacters($constraint, $requirements);
77
        }
78
79 2
        return $requirements;
80
    }
81
82 5
    public function getHintString(array $requirements = null)
83
    {
84 5
        if ($requirements === null) {
85 1
            $requirements = $this->getPasswordRequirements();
86
        }
87
88 5
        $reqs = [];
89 5
        if ($requirements['requireLetters']) {
90 1
            $reqs[] = $this->translator->trans('password_hint.requirements.letters');
91
        }
92 5
        if ($requirements['requireNumbers']) {
93 1
            $reqs[] = $this->translator->trans('password_hint.requirements.numbers');
94
        }
95 5
        if ($requirements['requireSpecialCharacter']) {
96 1
            $reqs[] = $this->translator->trans('password_hint.requirements.special');
97
        }
98
99 5
        if ($requirements['min'] > 0 && $requirements['max'] !== null) {
100 1
            $type = self::TRANS_TYPE_RANGE;
101 4
        } elseif ($requirements['min'] > 0 && $requirements['max'] === null) {
102 1
            $type = self::TRANS_TYPE_MIN;
103 3
        } elseif ($requirements['min'] <= 0 && $requirements['max'] !== null) {
104 1
            $type = self::TRANS_TYPE_MAX;
105
        } else {
106 2
            $type = self::TRANS_TYPE_NO_LIMIT;
107
        }
108
109 5
        if (count($reqs) > 1) {
110 1
            $reqString = sprintf(
111 1
                '%s %s %s',
112 1
                implode(', ', array_slice($reqs, 0, count($reqs) - 1)),
113 1
                $this->translator->trans('password_hint.and'),
114 1
                end($reqs)
115
            );
116
        } else {
117 4
            $reqString = reset($reqs);
118
        }
119
120 5
        $hasReqs = count($reqs) > 0 ? self::TRANS_WITH_REQS : self::TRANS_NO_REQS;
121
122
        $params = [
123 5
            '%reqs%' => $reqString,
124 5
            '%min%' => $requirements['min'],
125 5
            '%max%' => $requirements['max'],
126
        ];
127
128 5
        if ($type === self::TRANS_TYPE_NO_LIMIT && count($reqs) <= 0) {
129 1
            return false;
130
        }
131
132 4
        return $this->translator->trans("password_hint.{$type}.{$hasReqs}", $params);
133
    }
134
135 2
    private function checkMin(Constraint $constraint, array $requirements)
136
    {
137 2
        if (property_exists($constraint, 'min')) {
138 1
            $newMin = $constraint->min;
139 2
        } elseif (property_exists($constraint, 'minLength')) {
140 1
            $newMin = $constraint->minLength;
141
        } else {
142 1
            return $requirements;
143
        }
144 1
        if ($newMin > $requirements['min']) {
145 1
            $requirements['min'] = $newMin;
146
        }
147
148 1
        return $requirements;
149
    }
150
151 2
    private function checkMax(Constraint $constraint, array $requirements)
152
    {
153 2
        if (property_exists($constraint, 'max')) {
154 1
            $newMax = $constraint->max;
155
        } else {
156 2
            return $requirements;
157
        }
158 1
        if ($requirements['max'] === null || $newMax < $requirements['max']) {
159 1
            $requirements['max'] = $newMax;
160
        }
161
162 1
        return $requirements;
163
    }
164
165 2
    private function checkCharacters(Constraint $constraint, array $requirements)
166
    {
167 2
        if (!($constraint instanceof PasswordRequirements)) {
168 2
            return $requirements;
169
        }
170
171 1
        $requirements['requireLetters'] = $constraint->requireLetters;
172 1
        $requirements['requireNumbers'] = $constraint->requireNumbers;
173 1
        $requirements['requireSpecialCharacter'] = $constraint->requireSpecialCharacter;
174
175 1
        return $requirements;
176
    }
177
}
178