Issue 1461504 by joostvdl: Fix country list
[project/phone.git] / phone.module
1 <?php
2
3 /**
4 * Function which holds an array of supported countries.
5 *
6 * @param string $countrycode
7 * @return boolean Returns the whole array of countries $countrycode isn't specified and a country name for when it is specified.
8 */
9 function phone_countries($code = NULL) {
10 static $countries;
11
12 if (!isset($countries)) {
13 $countries = array(
14 'fr' => 'France',
15 'be' => 'Belgium',
16 'it' => 'Italy',
17 'el' => 'Greece',
18 'ch' => 'Switzerland',
19 'ca' => 'US & Canada',
20 'cr' => 'Costa Rica',
21 'pa' => 'Panama',
22 'gb' => 'Great Britain - United Kingdom',
23 'ru' => 'Russia',
24 'ua' => 'Ukraine',
25 'es' => 'Spain',
26 'au' => 'Australia',
27 'cs' => 'Czech Republic',
28 'hu' => 'Hungary',
29 'pl' => 'Poland - mobiles only',
30 'nl' => 'Netherland',
31 'se' => 'Sweden',
32 'za' => 'South Africa',
33 'il' => 'Israel',
34 'nz' => 'New Zealand',
35 'br' => 'Brazil',
36 'cl' => 'Chile',
37 'cn' => 'China',
38 'hk' => 'Hong-Kong',
39 'mo' => 'Macao',
40 'ph' => 'The Philippines',
41 'sg' => 'Singapore',
42 'jo' => 'Jordan',
43 'eg' => 'Egypt',
44 'pk' => 'Pakistan',
45 'int' => 'International Phone Numbers per E.123',
46 );
47 }
48 return ($code === NULL) ? $countries : (isset($countries[$code]) ? $countries[$code] : NULL);
49 }
50
51 /**
52 * @defgroup field_api_hooks Field API Hook Implementations
53 */
54
55 /**
56 * Implementation of hook_field_info().
57 */
58 function phone_field_info() {
59 return array(
60 'phone' => array(
61 'label' => t('Phone Number'),
62 'instance_settings' => array(
63 'phone_country_code' => 0,
64 'phone_default_country_code' => '1',
65 'phone_int_max_length' => 15,
66 'ca_phone_separator' => '-',
67 'ca_phone_parentheses' => 1,
68 ),
69 'default_formatter' => 'phone',
70 'default_widget' => 'phone_textfield',
71 'property_type' => 'text',
72 ),
73 );
74 }
75
76 /**
77 * Implements hook_field_is_empty().
78 */
79 function phone_field_is_empty($item, $field) {
80 return empty($item['value']);
81 }
82
83 /**
84 * Implements hook_field_settings_form().
85 */
86 function phone_field_settings_form($field, $instance, $has_data) {
87 $settings = $field['settings'];
88
89 $form = array();
90 $form['country'] = array(
91 '#type' => 'select',
92 '#title' => t('Country'),
93 '#options' => phone_countries(),
94 '#default_value' => isset ($settings['country']) ? $settings['country'] : NULL,
95 '#description' => t('Which country-specific rules should this field be validated against and formatted according to.'),
96 '#disabled' => $has_data,
97 '#required' => TRUE,
98 );
99
100 return $form;
101 }
102
103 /**
104 * Implements hook_field_instance_settings_form().
105 */
106 function phone_field_instance_settings_form($field, $instance) {
107 $settings = $instance['settings'];
108
109 $form['phone_country_code'] = array(
110 '#type' => 'checkbox',
111 '#title' => t('Add the country code if not filled by the user'),
112 '#default_value' => $settings['phone_country_code'],
113 );
114
115 if ($field['settings']['country'] == 'int') {
116 $form['phone_int_help'] = array(
117 '#type' => 'markup',
118 '#value' => t('International phone numbers are in the form +XX YYYYYYY where XX is a country code and YYYYYYY is the local number. This field type is based off of the <a href="http://www.itu.int/rec/T-REC-E.123/en">E.123 specification</a>.'),
119 );
120 $form['phone_default_country_code'] = array(
121 '#type' => 'textfield',
122 '#title' => t('Default country code to add to international numbers without one (omit + sign)'),
123 '#default_value' => $settings['phone_default_country_code'],
124 );
125 $form['phone_int_max_length'] = array(
126 '#type' => 'textfield',
127 '#title' => t('Maximum length of international numbers, according to the ITU this is 15'),
128 '#default_value' => $settings['phone_int_max_length'],
129 );
130 }
131
132 if ($field['settings']['country'] == 'ca') {
133 $form['ca_phone_separator'] = array(
134 '#type' => 'textfield',
135 '#title' => t('Separator'),
136 '#default_value' => $settings['ca_phone_separator'],
137 '#size' => 2,
138 );
139 $form['ca_phone_parentheses'] = array(
140 '#type' => 'checkbox',
141 '#title' => t('Use parentheses around area code'),
142 '#default_value' => $settings['ca_phone_parentheses'],
143 );
144 }
145 return $form;
146 }
147
148 /**
149 * Implements hook_field_validate().
150 */
151 function phone_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
152 foreach ($items as $delta => $item) {
153 if (isset($item['value']) && $item['value'] != '') {
154 $ccode = $field['settings']['country'];
155 $value = $item['value'];
156 if (!valid_phone_number($ccode, $value)) {
157 $country = phone_country_info($ccode);
158 $errors[$field['field_name']][$langcode][$delta][] = array(
159 'error' => t($country['error'], array('%value' => $value)),
160 );
161 }
162 }
163 }
164 }
165
166 /**
167 * Implements hook_field_presave().
168 */
169 function phone_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
170 $ccode = $field['settings']['country'];
171 if (phone_countries($ccode) !== NULL) {
172 foreach ($items as $delta => $item) {
173 if (isset($item['value'])) {
174 $items[$delta]['value'] = format_phone_number($ccode, $item['value'], $instance['settings']);
175 }
176 }
177 }
178 }
179
180 /**
181 * Implements hook_field_formatter_info().
182 */
183 function phone_field_formatter_info() {
184 return array(
185 'phone' => array(
186 'label' => t('Default'),
187 'field types' => array('phone'),
188 )
189 );
190 }
191
192 /**
193 * Implements hook_field_formatter_view().
194 */
195 function phone_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
196 $element = array();
197 foreach ($items as $delta => $item) {
198 $text = '';
199
200 if (isset($item['value'])) {
201 $text = check_plain($item['value']);
202 // iPhone Support
203 if (strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone') !== FALSE) {
204 $text = '<a href="tel:' . $text . '">' . $text . '</a>';
205 }
206 }
207 $element[$delta]['#markup'] = $text;
208 }
209 return $element;
210 }
211
212 /**
213 * Implements hook_field_widget_info().
214 */
215 function phone_field_widget_info() {
216 return array(
217 'phone_textfield' => array(
218 'label' => t('Text field'),
219 'field types' => array('phone'),
220 ),
221 );
222 }
223
224 /**
225 * Implements hook_field_widget_form().
226 */
227 function phone_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
228 $element['value'] = array(
229 '#type' => 'textfield',
230 '#title' => $element['#title'],
231 '#description' => $element['#description'],
232 '#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : '',
233 '#required' => $element['#required'],
234 '#size' => 17,
235 '#maxlength' => (
236 $field['settings']['country'] == 'int' ?
237 (isset($instance['settings']['phone_int_max_length']) ? $instance['settings']['phone_int_max_length'] : NULL)
238 : NULL
239 ),
240 );
241 return $element;
242 }
243
244 /**
245 * @} End of "defgroup field_api_hooks".
246 */
247
248
249 /**
250 * @defgroup other_hooks Other Hook Implementations
251 */
252
253 /**
254 * Implements hook_content_migrate_field_alter().
255 *
256 * Use this to tweak the conversion of field settings
257 * from the D6 style to the D7 style for specific
258 * situations not handled by basic conversion,
259 * as when field types or settings are changed.
260 */
261 function phone_content_migrate_field_alter(&$field_value, $instance_value) {
262 module_load_include('inc', 'phone', 'phone.migrate');
263 phone_field_alter($field_value, $instance_value);
264 }
265
266 /**
267 * Implementation of hook token_list
268 */
269 function phone_token_list($type = 'all') {
270 if ($type == 'field' || $type == 'all') {
271 $tokens['phone']['raw'] = t('Raw phone numbers');
272 $tokens['phone']['formatted'] = t('Formatted phone numbers');
273 return $tokens;
274 }
275 }
276
277 /**
278 * Implementation of hook token_values
279 */
280 function phone_token_values($type, $object = NULL, $options = array()) {
281 if ($type == 'field') {
282 $item = $object[0];
283 $tokens['raw'] = $item['value'];
284 $tokens['formatted'] = $item['view'];
285 return $tokens;
286 }
287 }
288
289 /**
290 * Implementation of hook_simpletest().
291 */
292 function phone_simpletest() {
293 $dir = drupal_get_path('module', 'phone'). '/tests';
294 $tests = file_scan_directory($dir, '\.test$');
295 return array_keys($tests);
296 }
297
298 /**
299 * @} End of "defgroup field_api_hooks".
300 */
301
302
303 /**
304 * Country supported or not by the module ?
305 *
306 * @param string $countrycode
307 * @return boolean Returns a boolean containting the answer to the question.
308 */
309 function phone_supported_countrycode($countrycode) {
310 return (phone_country_info($countrycode) !== NULL ? TRUE : FALSE);
311 }
312
313
314 /**
315 * Get a country meta info
316 *
317 * @param string $countrycode
318 * @return array Returns a array containing country metadata
319 */
320 function phone_country_info($countrycode = NULL) {
321 static $i;
322
323 $countrycode = trim($countrycode);
324
325 if (phone_countries($countrycode) !== FALSE) {
326 $phone_info_function = 'phone_'. $countrycode . '_metadata';
327 module_load_include('inc', 'phone', 'include/phone.'. $countrycode);
328
329 if (function_exists($phone_info_function)) {
330 return $phone_info_function();
331 }
332 }
333 //Country not taken into account yet
334 return FALSE;
335 }
336
337 /**
338 * Verification for Phone Numbers.
339 *
340 * @param string $countrycode
341 * @param string $phonenumber
342 * @return boolean Returns boolean FALSE if the phone number is not valid.
343 */
344 function valid_phone_number($countrycode, $phonenumber) {
345
346 $countrycode = trim($countrycode);
347 $phonenumber = trim($phonenumber);
348
349 if (phone_supported_countrycode($countrycode)) {
350 $valid_phone_function = 'valid_'. $countrycode . '_phone_number';
351 module_load_include('inc', 'phone', 'include/phone.'. $countrycode);
352
353 if (function_exists($valid_phone_function)) {
354 return $valid_phone_function($phonenumber);
355 }
356 }
357 //Country not taken into account yet
358 return FALSE;
359 }
360
361 /**
362 * Formatting for Phone Numbers.
363 *
364 * @param string $countrycode
365 * @param string $phonenumber
366 * @return boolean Returns boolean FALSE if the phone number is not valid.
367 */
368 function format_phone_number($countrycode, $phonenumber, $field) {
369
370 $countrycode = trim($countrycode);
371 $phonenumber = trim($phonenumber);
372
373 if (phone_supported_countrycode($countrycode)) {
374 $format_phone_function = 'format_'. $countrycode . '_phone_number';
375 module_load_include('inc', 'phone', 'include/phone.'. $countrycode);
376
377 if (function_exists($format_phone_function)) {
378 return $format_phone_function($phonenumber, $field);
379 }
380 }
381 //Country not taken into account yet
382 return FALSE;
383 }
384