Passed
Push — issue#767 ( 19cc40...08b279 )
by Guilherme
08:05
created

PasswordHintService::getPasswordRequirements()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

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