Passed
Push — master ( 0374f0...9ff869 )
by Thomas
13:12
created

PhoneField::setDisplayFormat()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
c 1
b 0
f 1
nc 1
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
namespace LeKoala\PhoneNumber;
4
5
use LeKoala\PhoneNumber\Test\PhoneNumberTest;
6
use SilverStripe\Forms\TextField;
7
use libphonenumber\PhoneNumberFormat;
8
use libphonenumber\NumberParseException;
9
use libphonenumber\PhoneNumber;
10
use libphonenumber\PhoneNumberType;
11
use SilverStripe\ORM\DataObject;
12
use SilverStripe\Forms\Validator;
13
14
/**
15
 * A simple phone field
16
 *
17
 * Formatting only works with international number because we don't know the country
18
 *
19
 * For national numbers, use CountryPhoneField that use a combination of CountryCode + PhoneNumber field
20
 */
21
class PhoneField extends TextField
22
{
23
    /**
24
     * @var string|null
25
     */
26
    protected $countryField = null;
27
28
    /**
29
     * @var string|null
30
     */
31
    protected $countryCode = null;
32
33
    /**
34
     * @var bool
35
     */
36
    protected $isMobile = false;
37
38
    /**
39
     * @var int
40
     */
41
    protected $displayFormat = 1; // INTERNATIONAL
42
43
    /**
44
     * @return string
45
     */
46
    public function getInputType()
47
    {
48
        return 'phone';
49
    }
50
51
    /**
52
     * @return string
53
     */
54
    public function Type()
55
    {
56
        return 'text';
57
    }
58
59
    /**
60
     * @param string $name
61
     * @param string|null $title
62
     * @param mixed $value
63
     */
64
    public function __construct($name, $title = null, $value = null)
65
    {
66
        // Autodetect mobile fields
67
        if (strpos(strtolower($name), 'mobile') !== false) {
68
            $this->isMobile = true;
69
        }
70
        parent::__construct($name, $title, $value);
71
    }
72
73
    /**
74
     * @param mixed $value Either the parent object, or array of source data being loaded
75
     * @param array<mixed>|DataObject|null $data {@see Form::loadDataFrom}
76
     * @return $this
77
     */
78
    public function setValue($value, $data = null)
79
    {
80
        $isInternational = strpos((string)$value, '+') === 0;
81
82
        if (!$isInternational && $this->countryField) {
83
            if (isset($data[$this->countryField])) {
84
                $countryValue = $data[$this->countryField];
85
                $this->countryCode = $countryValue;
86
87
                if (strpos((string)$countryValue, '+') === 0) {
88
                    // It's a + prefix, eg +33, +32
89
                    $value = $countryValue . ltrim((string)$value, "0");
90
                } elseif (is_numeric($countryValue)) {
91
                    // It's a plain prefix, eg 33, 32
92
                    $value = '+' . $countryValue . ltrim((string)$value, "0");
93
                } else {
94
                    // It's a country code (FR, BE...)
95
                    $countryValue = PhoneHelper::convertCountryCodeToPrefix($countryValue);
96
                    if ($countryValue) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $countryValue of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
97
                        $value = '+' . $countryValue . ltrim((string)$value, "0");
98
                    }
99
                }
100
            }
101
102
            // Test again!
103
            $isInternational = strpos((string)$value, '+') === 0;
104
        }
105
106
        // We have an international number that we can format easily without knowing the country
107
        if ($isInternational) {
108
            $util = PhoneHelper::getPhoneNumberUtil();
109
            try {
110
                $number = $util->parse($value);
111
                $newValue = $util->format($number, $this->displayFormat);
112
            } catch (NumberParseException $ex) {
113
                $newValue = $value;
114
            }
115
            $value = $newValue;
116
        }
117
        return parent::setValue($value, $data);
118
    }
119
120
    /**
121
     * Validate this field
122
     *
123
     * @param Validator $validator
124
     * @return bool
125
     */
126
    public function validate($validator)
127
    {
128
        if ($this->isMobile && $this->value) {
129
            $util = PhoneHelper::getPhoneNumberUtil();
130
            $number = $util->parse($this->value, $this->countryCode);
131
            $type = $util->getNumberType($number);
132
            if (!in_array($type, [PhoneNumberType::FIXED_LINE_OR_MOBILE, PhoneNumberType::MOBILE])) {
133
                $validator->validationError(
134
                    $this->name,
135
                    _t('PhoneField.IsNotAMobileNumber', 'This is not a valid mobile number')
136
                );
137
            }
138
        }
139
        return parent::validate($validator);
140
    }
141
142
    /**
143
     * Value in E164 format (no formatting)
144
     *
145
     * @return string
146
     */
147
    public function dataValue()
148
    {
149
        $value = $this->Value();
150
151
        // It's an international number or we have a country set, format without spaces
152
        if (strpos((string)$value, '+') === 0 || $this->countryCode) {
153
            $util = PhoneHelper::getPhoneNumberUtil();
154
            try {
155
                $number = $util->parse($value, $this->countryCode);
156
                $formatted = $util->format($number, PhoneNumberFormat::E164);
157
            } catch (NumberParseException $ex) {
158
                $formatted = $value;
159
            }
160
            return $formatted;
161
        }
162
        return $value;
163
    }
164
165
    /**
166
     * Name of the country field
167
     *
168
     * @return string
169
     */
170
    public function getCountryField()
171
    {
172
        return $this->countryField;
173
    }
174
175
    /**
176
     * Name of the country field
177
     *
178
     * @param string $countryField
179
     * @return $this
180
     */
181
    public function setCountryField($countryField)
182
    {
183
        $this->countryField = $countryField;
184
        return $this;
185
    }
186
187
    /**
188
     * @return string
189
     */
190
    public function getCountryCode()
191
    {
192
        return $this->countryCode;
193
    }
194
195
    /**
196
     * @param string $countryCode
197
     * @return $this
198
     */
199
    public function setCountryCode($countryCode)
200
    {
201
        $this->countryCode = $countryCode;
202
        return $this;
203
    }
204
205
    /**
206
     * Get the value of isMobile
207
     * @return bool
208
     */
209
    public function getIsMobile()
210
    {
211
        return $this->isMobile;
212
    }
213
214
    /**
215
     * Set the value of isMobile
216
     *
217
     * @param bool $isMobile
218
     * @return $this
219
     */
220
    public function setIsMobile(bool $isMobile)
221
    {
222
        $this->isMobile = $isMobile;
223
        return $this;
224
    }
225
226
    /**
227
     * Get the value of displayFormat
228
     *
229
     * @return int
230
     */
231
    public function getDisplayFormat()
232
    {
233
        return $this->displayFormat;
234
    }
235
236
    /**
237
     * Set the value of displayFormat
238
     *
239
     * @param int $displayFormat
240
     * @return $this
241
     */
242
    public function setDisplayFormat($displayFormat)
243
    {
244
        $this->displayFormat = $displayFormat;
245
        return $this;
246
    }
247
}
248