Completed
Push — master ( c130e5...a809e8 )
by Sam
10:09
created

PhoneNumberField   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 246
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 246
rs 8.3999
wmc 38
lcom 1
cbo 6

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getCountryField() 0 3 1
A getAreaField() 0 3 1
A getNumberField() 0 3 1
A getExtensionField() 0 3 1
A getChildField() 0 11 3
B __construct() 0 37 5
A setName() 0 9 2
A hasData() 0 3 1
A Field() 0 9 2
A setValue() 0 15 4
B joinPhoneNumber() 0 22 5
B parseValue() 0 20 7
A saveInto() 0 4 1
A validate() 0 17 2
A performReadonlyTransformation() 0 7 1
A performDisabledTransformation() 0 7 1
1
<?php
2
3
use SilverStripe\ORM\DataObjectInterface;
4
5
/**
6
 * @package forms
7
 * @subpackage fields-formattedinput
8
 */
9
10
/**
11
 * Field for displaying phone numbers. It separates the number, the area code and optionally the country code
12
 * and extension.
13
 * @package forms
14
 * @subpackage fields-formattedinput
15
 */
16
class PhoneNumberField extends FieldGroup {
17
18
	/**
19
	 * Default area code
20
	 *
21
	 * @var string
22
	 */
23
	protected $areaCode;
24
25
	/**
26
	 * Default country code
27
	 * @var string
28
	 */
29
	protected $countryCode;
30
31
	/**
32
	 * Default extension
33
	 *
34
	 * @var string
35
	 */
36
	protected $ext;
37
38
	/**
39
	 * @return NumericField
40
	 */
41
	public function getCountryField() {
42
		return $this->getChildField('Country');
43
	}
44
45
	/**
46
	 * @return NumericField
47
	 */
48
	public function getAreaField() {
49
		return $this->getChildField('Area');
50
	}
51
52
	/**
53
	 * @return NumericField
54
	 */
55
	public function getNumberField() {
56
		return $this->getChildField('Number');
57
	}
58
59
	/**
60
	 * @return NumericField
61
	 */
62
	public function getExtensionField() {
63
		return $this->getChildField('Extension');
64
	}
65
66
	protected function getChildField($name) {
67
		$endsWith = "[{$name}]";
68
		foreach($this->getChildren() as $child) {
69
70
			/** @var Formfield $child */
71
			if(substr($child->getName(), 0 - strlen($endsWith)) === $endsWith) {
72
				return $child;
73
			}
74
		}
75
		return null;
76
	}
77
78
	public function __construct(
79
		$name, $title = null, $value = '', $extension = null, $areaCode = null, $countryCode = null
80
	) {
81
		$this->areaCode = $areaCode;
82
		$this->ext = $extension;
83
		$this->countryCode = $countryCode;
84
85
		// Build fields
86
		$fields = new FieldList();
87
		if($this->countryCode !== null) {
88
			$countryField = NumericField::create($name.'[Country]', false, $countryCode, 4)
89
				->addExtraClass('phonenumber-field__country');
90
			$fields->push($countryField);
91
		}
92
93
		if($this->areaCode !== null) {
94
			$areaField = NumericField::create($name.'[Area]', false, $areaCode, 4)
95
				->addExtraClass('phonenumber-field__area');
96
			$fields->push($areaField);
97
		}
98
		$numberField = NumericField::create($name.'[Number]', false, null, 10)
99
			->addExtraClass('phonenumber-field__number');
100
		$fields->push($numberField);
101
102
		if($this->ext !== null) {
103
			$extensionField = NumericField::create( $name.'[Extension]', false, $extension, 6)
104
				->addExtraClass('phonenumber-field__extension');
105
			$fields->push($extensionField);
106
		}
107
108
		parent::__construct($title, $fields);
109
110
		$this->setName($name);
111
		if (isset($value)) {
112
			$this->setValue($value);
113
		}
114
	}
115
116
	public function setName($name) {
117
		parent::setName($name);
118
		foreach($this->getChildren() as $child) {
119
			/** @var FormField $child */
120
			$thisName = $child->getName();
121
			$thisName = preg_replace('/^.*(\[\\w+\\])$/', $name . '\\1', $thisName);
122
			$child->setName($thisName);
123
		}
124
	}
125
126
	public function hasData() {
127
		return true;
128
	}
129
130
	/**
131
	 * @param array $properties
132
	 * @return string
133
	 */
134
	public function Field($properties = array()) {
135
		foreach($this->getChildren() as $field) {
136
			/** @var FormField $field */
137
			$field->setDisabled($this->isDisabled());
138
			$field->setReadonly($this->IsReadonly());
139
			$field->setForm($this->getForm());
140
		}
141
		return parent::Field($properties);
142
	}
143
144
	public function setValue( $value ) {
145
		$this->value = self::joinPhoneNumber( $value );
146
		$parts = $this->parseValue();
147
		if($countryField = $this->getCountryField()) {
148
			$countryField->setValue($parts['Country']);
149
		}
150
		if($areaField = $this->getAreaField()) {
151
			$areaField->setValue($parts['Area']);
152
		}
153
		$this->getNumberField()->setValue($parts['Number']);
154
		if ($extensionField = $this->getExtensionField()) {
155
			$extensionField->setValue($parts['Extension']);
156
		}
157
		return $this;
158
	}
159
160
	/**
161
	 * Join phone number into a string
162
	 *
163
	 * @param array|string $value Input
164
	 * @return string
165
	 */
166
	public static function joinPhoneNumber( $value ) {
167
		if( is_array( $value ) ) {
168
			$completeNumber = '';
169
			if( !empty($value['Country'])) {
170
				$completeNumber .= '+' . $value['Country'];
171
			}
172
173
			if( !empty($value['Area'])) {
174
				$completeNumber .= '(' . $value['Area'] . ')';
175
			}
176
177
			$completeNumber .= $value['Number'];
178
179
			if( !empty($value['Extension']) ) {
180
				$completeNumber .= '#' . $value['Extension'];
181
			}
182
183
			return $completeNumber;
184
		} else {
185
			return $value;
186
		}
187
	}
188
189
	/**
190
	 * Returns array with parsed phone format
191
	 *
192
	 * @return array Array with Country, Area, Number, and Extension keys (in order)
193
	 */
194
	protected function parseValue() {
195
		if (is_array($this->value)) {
196
			return $this->value;
197
		}
198
		// Parse value in form "+ countrycode (areacode) phone # extension"
199
		$valid = preg_match(
200
			'/^(?:(?:\+(?<Country>\d+))?\s*\((?<Area>\d+)\))?\s*(?<Number>[0-9A-Za-z]*)\s*(?:[#]\s*(?<Extension>\d+))?$/',
201
			$this->value,
202
			$parts
203
		);
204
		if(!$valid) {
205
			$parts = [];
206
		}
207
		return array(
208
			'Country' => isset($parts['Country']) ? $parts['Country'] : '',
209
			'Area' => isset($parts['Area']) ? $parts['Area'] : '',
210
			'Number' => isset($parts['Number']) ? $parts['Number'] : '',
211
			'Extension' => isset($parts['Extension']) ? $parts['Extension'] : '',
212
		);
213
	}
214
215
	public function saveInto(DataObjectInterface $record) {
216
		$completeNumber = static::joinPhoneNumber($this->parseValue());
217
		$record->setCastedField($this->getName(), $completeNumber);
218
	}
219
220
	/**
221
	 * Validate this field
222
	 *
223
	 * @todo Very basic validation at the moment
224
	 *
225
	 * @param Validator $validator
226
	 * @return bool
227
	 */
228
	public function validate($validator){
229
		$valid = preg_match(
230
			'/^[0-9\+\-\(\)\s\#]*$/',
231
			$this->joinPhoneNumber($this->value)
232
		);
233
234
		if(!$valid){
235
			$validator->validationError(
236
				$this->name,
237
				_t('PhoneNumberField.VALIDATION', "Please enter a valid phone number"),
238
				"validation"
239
			);
240
			return false;
241
		}
242
243
		return true;
244
	}
245
246
	public function performReadonlyTransformation()
247
	{
248
		// Just setReadonly without casting to NumericField_Readonly
249
		$clone = clone $this;
250
		$clone->setReadonly(true);
251
		return $clone;
252
	}
253
254
	public function performDisabledTransformation()
255
	{
256
		// Just setDisabled without casting to NumericField_Disabled
257
		$clone = clone $this;
258
		$clone->setDisabled(true);
259
		return $clone;
260
	}
261
}
262