Completed
Push — master ( 96acaf...3216da )
by
unknown
13s queued 11s
created

PhoneFilter::getValueAsString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 8
rs 10
1
<?php
2
3
4
namespace TraderInteractive\Filter;
5
6
use Throwable;
7
use TraderInteractive\Exceptions\FilterException;
8
9
final class PhoneFilter
10
{
11
12
    /**
13
     * The pattern for the separations between numbers.
14
     *
15
     * @var string
16
     */
17
    const SEPARATOR_PATTERN = ' *[-.]? *';
18
19
    /**
20
     * The pattern for the area code.
21
     *
22
     * @var string
23
     */
24
    const AREA_CODE_PATTERN = '(?:\(([2–9]\d\d)\)|([2-9]\d\d))?';
25
26
    /**
27
     * The pattern for the exchange code. Also known as the central office code.
28
     *
29
     * @var string
30
     */
31
    const EXCHANGE_CODE_PATTERN = '([2-9]\d\d)';
32
33
    /**
34
     * The pattern for the station code. Also known as the line number or subscriber number.
35
     *
36
     * @var string
37
     */
38
    const STATION_CODE_PATTERN = '(\d{4})';
39
40
    /**
41
     * The pattern for phone numbers according to the North American Numbering Plan specification.
42
     *
43
     * @var string
44
     */
45
    const PHONE_PATTERN = (''
46
        . '/^ *'
47
        . self::AREA_CODE_PATTERN
48
        . self::SEPARATOR_PATTERN
49
        . self::EXCHANGE_CODE_PATTERN
50
        . self::SEPARATOR_PATTERN
51
        . self::STATION_CODE_PATTERN
52
        . ' *$/'
53
    );
54
55
    /**
56
     * @var string
57
     */
58
    const ERROR_INVALID_PHONE_NUMBER = "Value '%s' is not a valid phone number.";
59
60
    /**
61
     * @var string
62
     */
63
    const ERROR_VALUE_CANNOT_BE_NULL = 'Value cannot be null';
64
65
    /**
66
     * @var string
67
     */
68
    const DEFAULT_FILTERED_PHONE_FORMAT = '{area}{exchange}{station}';
69
70
    /**
71
     * @var bool
72
     */
73
    private $allowNull;
74
75
    /**
76
     * @var string
77
     */
78
    private $filteredPhoneFormat;
79
80
    /**
81
     * @param bool   $allowNull           Flag to allow value to be null
82
     * @param string $filteredPhoneFormat The format for which the filtered phone value will be returned.
83
     */
84
    public function __construct(
85
        bool $allowNull = false,
86
        string $filteredPhoneFormat = self::DEFAULT_FILTERED_PHONE_FORMAT
87
    ) {
88
        $this->allowNull = $allowNull;
89
        $this->filteredPhoneFormat = $filteredPhoneFormat;
90
    }
91
92
    /**
93
     * @param mixed  $value The value to filter.
94
     *
95
     * @return string|null
96
     *
97
     * @throws FilterException Thrown when the value does not pass filtering.
98
     */
99
    public function __invoke($value)
100
    {
101
        return self::filter($value, $this->allowNull, $this->filteredPhoneFormat);
102
    }
103
104
    /**
105
     * @param mixed  $value               The value to filter.
106
     * @param bool   $allowNull           Flag to allow value to be null
107
     * @param string $filteredPhoneFormat The format for which the filtered phone value will be returned.
108
     *
109
     * @return string|null
110
     *
111
     * @throws FilterException Thrown when the value does not pass filtering.
112
     */
113
    public static function filter(
114
        $value,
115
        bool $allowNull = false,
116
        string $filteredPhoneFormat = self::DEFAULT_FILTERED_PHONE_FORMAT
117
    ) {
118
        if ($value === null) {
119
            return self::returnNullValue($allowNull);
0 ignored issues
show
Bug introduced by
Are you sure the usage of self::returnNullValue($allowNull) targeting TraderInteractive\Filter...lter::returnNullValue() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
120
        }
121
122
        $value = self::getValueAsString($value);
123
        $matches = [];
124
        if (!preg_match(self::PHONE_PATTERN, $value, $matches)) {
125
            $message = sprintf(self::ERROR_INVALID_PHONE_NUMBER, $value);
126
            throw new FilterException($message);
127
        }
128
129
        list($phone, $areaWithParenthesis, $area, $exchange, $station) = $matches;
130
        if ($areaWithParenthesis !== '') {
131
            $area = $areaWithParenthesis;
132
        }
133
134
        $search = ['{area}', '{exchange}', '{station}'];
135
        $replace = [$area, $exchange, $station];
136
        return str_replace($search, $replace, $filteredPhoneFormat);
137
    }
138
139
    private static function returnNullValue(bool $allowNull)
140
    {
141
        if ($allowNull === false) {
142
            throw new FilterException(self::ERROR_VALUE_CANNOT_BE_NULL);
143
        }
144
145
        return null;
146
    }
147
148
    private static function getValueAsString($value) : string
149
    {
150
        if (is_scalar($value)) {
151
            return (string)$value;
152
        }
153
154
        $message = sprintf(self::ERROR_INVALID_PHONE_NUMBER, var_export($value, true));
155
        throw new FilterException($message);
156
    }
157
}
158