Failed Conditions
Push — issue#767 ( 50d9b1...25878f )
by Guilherme
07:31
created

PasswordHintService::getHintString()   F

Complexity

Conditions 15
Paths 512

Size

Total Lines 51
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 240

Importance

Changes 0
Metric Value
cc 15
eloc 33
nc 512
nop 1
dl 0
loc 51
ccs 0
cts 31
cp 0
crap 240
rs 3.5184
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\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
    public function __construct(ValidatorInterface $validator, TranslatorInterface $translator, $userClass)
44
    {
45
        $this->validator = $validator;
46
        $this->translator = $translator;
47
        $this->userClass = $userClass;
48
    }
49
50
    public function getPasswordRequirements()
51
    {
52
        $requirements = [
53
            'min' => 0,
54
            'max' => null,
55
            'requireLetters' => false,
56
            'requireNumbers' => false,
57
            'requireSpecialCharacter' => false,
58
        ];
59
60
        /** @var ClassMetadata $metadata */
61
        $metadata = $this->validator->getMetadataFor($this->userClass);
62
63
        if (!($metadata instanceof ClassMetadata) || false === $metadata->hasPropertyMetadata('plainPassword')) {
0 ignored issues
show
introduced by
$metadata is always a sub-type of Symfony\Component\Validator\Mapping\ClassMetadata.
Loading history...
64
            return $requirements;
65
        }
66
        $propertyMetadata = $metadata->getPropertyMetadata('plainPassword');
67
        $constraints = [];
68
        foreach ($propertyMetadata as $propertymetadata) {
69
            $constraints = array_merge($constraints, $propertymetadata->getConstraints());
70
        }
71
72
        foreach ($constraints as $constraint) {
73
            $requirements = $this->checkMin($constraint, $requirements);
74
            $requirements = $this->checkMax($constraint, $requirements);
75
            $requirements = $this->checkCharacters($constraint, $requirements);
76
        }
77
78
        return $requirements;
79
    }
80
81
    public function getHintString(array $requirements = null)
82
    {
83
        if ($requirements === null) {
84
            $requirements = $this->getPasswordRequirements();
85
        }
86
87
        $reqs = [];
88
        if ($requirements['requireLetters']) {
89
            $reqs[] = $this->translator->trans('password_hint.requirements.letters');
90
        }
91
        if ($requirements['requireNumbers']) {
92
            $reqs[] = $this->translator->trans('password_hint.requirements.numbers');
93
        }
94
        if ($requirements['requireSpecialCharacter']) {
95
            $reqs[] = $this->translator->trans('password_hint.requirements.special');
96
        }
97
98
        if ($requirements['min'] > 0 && $requirements['max'] !== null) {
99
            $type = self::TRANS_TYPE_RANGE;
100
        } elseif ($requirements['min'] > 0 && $requirements['max'] === null) {
101
            $type = self::TRANS_TYPE_MIN;
102
        } elseif ($requirements['min'] <= 0 && $requirements['max'] !== null) {
103
            $type = self::TRANS_TYPE_MAX;
104
        } else {
105
            $type = self::TRANS_TYPE_NO_LIMIT;
106
        }
107
108
        if (count($reqs) > 1) {
109
            $reqString = sprintf(
110
                '%s %s %s',
111
                implode(', ', array_slice($reqs, 0, count($reqs) - 1)),
112
                $this->translator->trans('password_hint.and'),
113
                end($reqs)
114
            );
115
        } else {
116
            $reqString = reset($reqs);
117
        }
118
119
        $hasReqs = count($reqs) > 0 ? self::TRANS_WITH_REQS : self::TRANS_NO_REQS;
120
121
        $params = [
122
            '%reqs%' => $reqString,
123
            '%min%' => $requirements['min'],
124
            '%max%' => $requirements['max'],
125
        ];
126
127
        if ($type === self::TRANS_TYPE_NO_LIMIT && count($reqs) <= 0) {
128
            return false;
129
        }
130
131
        return $this->translator->trans("password_hint.{$type}.{$hasReqs}", $params);
132
    }
133
134
    private function checkMin(Constraint $constraint, array $requirements)
135
    {
136
        if (property_exists($constraint, 'min')) {
137
            $newMin = $constraint->min;
138
        } elseif (property_exists($constraint, 'minLength')) {
139
            $newMin = $constraint->minLength;
140
        } else {
141
            return $requirements;
142
        }
143
        if ($newMin > $requirements['min']) {
144
            $requirements['min'] = $newMin;
145
        }
146
147
        return $requirements;
148
    }
149
150
    private function checkMax(Constraint $constraint, array $requirements)
151
    {
152
        if (property_exists($constraint, 'max')) {
153
            $newMax = $constraint->max;
154
        } else {
155
            return $requirements;
156
        }
157
        if ($requirements['max'] === null || $newMax < $requirements['max']) {
158
            $requirements['max'] = $newMax;
159
        }
160
161
        return $requirements;
162
    }
163
164
    private function checkCharacters(Constraint $constraint, array $requirements)
165
    {
166
        if (!($constraint instanceof PasswordRequirements)) {
167
            return $requirements;
168
        }
169
170
        $requirements['requireLetters'] = $constraint->requireLetters;
171
        $requirements['requireNumbers'] = $constraint->requireNumbers;
172
        $requirements['requireSpecialCharacter'] = $constraint->requireSpecialCharacter;
173
174
        return $requirements;
175
    }
176
}
177