Completed
Branch dev-v3 (d0b49e)
by Propa
01:27
created

Phone::validate()   C

Complexity

Conditions 13
Paths 26

Size

Total Lines 54
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 13

Importance

Changes 0
Metric Value
cc 13
eloc 25
nc 26
nop 4
dl 0
loc 54
ccs 20
cts 20
cp 1
crap 13
rs 6.7593
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 namespace Propaganistas\LaravelPhone\Validation;
2
3
use Illuminate\Support\Arr;
4
use Illuminate\Support\Collection;
5
use libphonenumber\PhoneNumberUtil;
6
use Propaganistas\LaravelPhone\Exceptions\InvalidParameterException;
7
use Propaganistas\LaravelPhone\Exceptions\CountryCodeException;
8
use Propaganistas\LaravelPhone\Exceptions\NumberParseException;
9
use Propaganistas\LaravelPhone\PhoneNumber;
10
use Propaganistas\LaravelPhone\Traits\ParsesCountries;
11
use Propaganistas\LaravelPhone\Traits\ParsesTypes;
12
13
class Phone
14
{
15
    use ParsesCountries,
16
        ParsesTypes;
17
18
    /**
19
     * @var \libphonenumber\PhoneNumberUtil
20
     */
21
    protected $lib;
22
23
    /**
24
     * Phone constructor.
25
     */
26 30
    public function __construct()
27
    {
28 30
        $this->lib = PhoneNumberUtil::getInstance();
29 30
    }
30
31
    /**
32
     * Validates a phone number.
33
     *
34
     * @param  string $attribute
35
     * @param  mixed  $value
36
     * @param  array  $parameters
37
     * @param  object $validator
38
     * @return bool
39
     */
40 30
    public function validate($attribute, $value, array $parameters, $validator)
41
    {
42 30
        $data = $validator->getData();
43
44
        list(
45
            $countries,
46
            $types,
47
            $detect,
48 30
            $lenient) = $this->extractParameters($attribute, $parameters, $data);
49
50
        // A "null" country is prepended:
51
        // 1. In case of auto-detection to have the validation run first without supplying a country.
52
        // 2. In case of lenient validation without provided countries; we still might have some luck...
53 27
        if ($detect || ($lenient && empty($countries))) {
54 6
            array_unshift($countries, null);
55
        }
56
57 27
        foreach ($countries as $country) {
58
            try {
59
                // Parsing the phone number also validates the country, so no need to do this explicitly.
60
                // It'll throw a PhoneCountryException upon failure.
61 24
                $phoneNumber = PhoneNumber::make($value, $country);
62
63
                // Type validation.
64 24
                if (! empty($types) && ! $phoneNumber->isOfType($types)) {
65 12
                    continue;
66
                }
67
68 24
                $lenientPhoneNumber = $phoneNumber->lenient()->getPhoneNumberInstance();
69
70
                // Lenient validation.
71 24
                if ($lenient && $this->lib->isPossibleNumber($lenientPhoneNumber, $country)) {
72 3
                    return true;
73
                }
74
75 24
                $phoneNumberInstance = $phoneNumber->getPhoneNumberInstance();
76
77
78
                // Country detection.
79 24
                if ($detect && $this->lib->isValidNumber($phoneNumberInstance)) {
80 3
                    return true;
81
                }
82
83
                // Default number+country validation.
84 24
                if ($this->lib->isValidNumberForRegion($phoneNumberInstance, $country)) {
85 24
                    return true;
86
                }
87 18
            } catch (NumberParseException $e) {
88 24
                continue;
89
            }
90
        }
91
92 27
        return false;
93
    }
94
95
    /**
96
     * Parse and extract parameters in the appropriate validation arguments.
97
     *
98
     * @param string $attribute
99
     * @param array  $parameters
100
     * @param array  $data
101
     * @return array
102
     * @throws \Propaganistas\LaravelPhone\Exceptions\InvalidParameterException
103
     */
104 30
    protected function extractParameters($attribute, array $parameters, array $data)
105
    {
106
        // Discover if an input field was provided. If not, guess the field's name.
107 30
        $inputField = Collection::make($parameters)
108 30
                                ->intersect(array_keys(Arr::dot($data)))
109 30
                                ->first(null, "${attribute}_country");
110
111
        // Attempt to retrieve the field's value. If no field is present, this will be null.
112
        $inputCountry = Arr::get($data, $inputField);
113
114
        $countries = static::parseCountries($inputCountry ? [$inputCountry] : $parameters);
115
        $types = static::parseTypes($parameters);
116
117
        // Force developers to write proper code.
118
        // Since the static parsers return a validated array with preserved keys, we can safely diff against the keys.
119
        $leftovers = Collection::make($parameters)
120
                               ->diffKeys($types)
121
                               ->diffKeys($inputCountry ? [] : $countries)
122
                               ->diff(['AUTO', 'LENIENT', $inputField]);
123
124
        if ($leftovers->isNotEmpty()) {
125
            throw InvalidParameterException::parameters($leftovers);
126
        }
127
128
        return [
129
            $countries,
130
            $types,
131
            in_array('AUTO', $parameters),
132
            in_array('LENIENT', $parameters),
133
            $inputField,
134
        ];
135
    }
136
}