? phone-1.patch
Index: README.int.txt
===================================================================
RCS file: README.int.txt
diff -N README.int.txt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ README.int.txt 21 Jan 2008 22:56:12 -0000
@@ -0,0 +1,56 @@
+About the International Phone Number format
+===========================================
+
+These rules have been formulated off of the E.123 (for display) and
+E.164 (for input) specifications published by the ITU. In order to
+prevent ambiguity, we have chosen to restrict some of the stipulations
+these specifications give.
+
+Reference materials can be found here:
+- http://www.itu.int/rec/T-REC-E.123/en
+- http://www.itu.int/rec/T-REC-E.164/en
+
+Modifications to E.123
+----------------------
+
+7.1: The international prefix symbol "+" MUST prefix international
+phone numbers. All numbers missing this symbol will be assumed to be in
+the default country code.
+
+When reformatting numbers to a standard format, the following conventions
+will be taken:
+
+7.2: Parentheses will be normalized to spaces.
+
+We do not support the multiple phone numbers as described by (7.4); users
+can always specify that multiple values are allowed if this is desired.
+The functionality specified by 7.5, 7.6 and 8 IS NOT implemented.
+
+9.2 specifies that spacing SHALL OCCUR between the country code, the trunk
+code and the subscriber number. As trunk codes are omitted by convention,
+this means the only guaranteed separation will be between the country code
+and subscriber number. Our implementation MAY treat hyphens, spaces and
+parentheses as advisory indicators as to where spaces should be placed.
+However, +1 7329060489 will stay as it was specified, while +1 (732) 906-0489
+will be normalized to +1 732 906 0489. As a future feature, rules may
+be implemented for country codes specifying these conventions, however,
+I have deemed such functionality out of scope for now.
+
+The Drupal task specifies that we should validate country codes, however,
+due to the highly volatile nature of these codes, the author does not
+believe that it is a good idea to maintain a list of valid country codes.
+Thus, we only validate that the country code is three or less digits.
+
+Modifications to E.164
+----------------------
+
+Our processing for NDD's will be similarly constrained. As per
+7.3.2, we will treat 0 as a valid trunk code for all countries.
+Other digits may be specified if the fall in the form of (X), where X is
+a single digit that is 7 or 8.
+
+Postscript
+----------
+
+Modifications to our implementation will occur as necessary by user bug
+reports.
\ No newline at end of file
Index: README.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/phone/README.txt,v
retrieving revision 1.1.1.3.2.3
diff -u -r1.1.1.3.2.3 README.txt
--- README.txt 23 Dec 2007 15:31:07 -0000 1.1.1.3.2.3
+++ README.txt 21 Jan 2008 22:14:35 -0000
@@ -9,7 +9,7 @@
Features:
---------
-* Validation of phone numbers : support of French, British, Italian, Russian, US and Canadian phone numbers
+* Validation of phone numbers : support of French, British, Italian, Russian, US, Canadian and generic international phone numbers
* Formating of phone numbers
* Option for internationalization phone numbers
* IPhone support
Index: phone.int.inc
===================================================================
RCS file: phone.int.inc
diff -N phone.int.inc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ phone.int.inc 21 Jan 2008 22:51:50 -0000
@@ -0,0 +1,73 @@
+ 15) return false;
+ // Extract country code and see if it's correct
+ preg_match('/^\+(\d+)/', $number, $matches);
+ $cc = $matches[1];
+ if (strlen($cc) > 3) return false;
+ // TODO: Check if parentheses/brackets add up
+ return true;
+}
+
+/**
+ * Formats $number into the standard representation of international
+ * numbers as per E.123.
+ *
+ * @param $number
+ * International phone number to format
+ * @return
+ * Formatted international phone number
+ */
+function format_int_phone_number($number, $field = array()) {
+ $number = trim($number);
+ if ($number === '') return '';
+ $number = _normalize_country_code($number, $field);
+ $bits = preg_split('/[.()\[\]\- ]/', $number, -1, PREG_SPLIT_NO_EMPTY);
+ // $bits[0] is the country code WITH a plus sign
+ if (isset($bits[1])) {
+ // This is the first non-CC segment, so it could have the NDN
+ switch ($bits[1][0]) {
+ case 0:
+ $bits[1] = substr($bits[1], 1);
+ break;
+ }
+ switch ($bits[1]) {
+ case 0:
+ case 7:
+ case 8:
+ array_splice($bits, 1, 1);
+ break;
+ }
+ }
+ return implode(' ', $bits);
+}
+
+/**
+ * Adds a country code to a phone number if necessary.
+ *
+ * @param $number
+ * International or local phone number to format
+ * @return
+ * International phone number with country code
+ */
+function _normalize_country_code($number, $field = array()) {
+ if ($number[0] !== '+') {
+ $cc = isset($field['phone_default_country_code']) ? $field['phone_default_country_code'] : '1';
+ return "+$cc $number";
+ }
+ return $number;
+}
Index: phone.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/phone/phone.module,v
retrieving revision 1.1.1.5.2.8
diff -u -r1.1.1.5.2.8 phone.module
--- phone.module 23 Dec 2007 15:31:07 -0000 1.1.1.5.2.8
+++ phone.module 21 Jan 2008 22:50:40 -0000
@@ -20,6 +20,7 @@
'ca_phone' => array('label' => t('US & Canadian Phone Numbers')),
'uk_phone' => array('label' => t('British (UK) Phone Numbers')),
'ru_phone' => array('label' => t('Russian Phone Numbers')),
+ 'int_phone'=> array('label' => t('International Phone Numbers')),
);
}
@@ -34,18 +35,26 @@
'#type' => 'checkbox',
'#title' => t('Add the country code if not filled by the user'),
'#default_value' => isset($field['phone_country_code']) ? $field['phone_country_code'] : '',
- );
+ );
+ if ($field['type'] == 'int_phone') {
+ $form['phone_default_country_code'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Default country code to add to international numbers without one (omit + sign)'),
+ '#default_value' => isset($field['phone_default_country_code']) ? $field['phone_default_country_code'] : '1',
+ );
+ }
return $form;
case 'save':
- return array('phone_country_code');
+ return array('phone_country_code', 'phone_default_country_code');
case 'database columns':
if ($field['type'] == 'fr_phone'
|| $field['type'] == 'it_phone'
|| $field['type'] == 'ca_phone'
|| $field['type'] == 'uk_phone'
- || $field['type'] == 'ru_phone'){
+ || $field['type'] == 'ru_phone'
+ || $field['type'] == 'int_phone'){
$columns = array(
'value' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE),
);
@@ -85,7 +94,7 @@
return array(
'default' => array(
'label' => 'Default',
- 'field types' => array('fr_phone', 'it_phone', 'ca_phone', 'uk_phone', 'ru_phone'),
+ 'field types' => array('fr_phone', 'it_phone', 'ca_phone', 'uk_phone', 'ru_phone', 'int_phone'),
),
);
}
@@ -117,7 +126,7 @@
return array(
'phone' => array(
'label' => t('Textfield'),
- 'field types' => array('fr_phone', 'it_phone', 'ca_phone', 'uk_phone', 'ru_phone'),
+ 'field types' => array('fr_phone', 'it_phone', 'ca_phone', 'uk_phone', 'ru_phone', 'int_phone'),
),
);
}
@@ -179,55 +188,44 @@
return $form;
case 'process form values':
- if (is_array($node_field)) {
- foreach ($node_field as $delta => $item) {
- //format the phone number
- if ($item['value'] != '')
- {
- if ($field['type'] == 'fr_phone') {
- $node_field[0]['value'] = format_phone_number('fr', $node_field[0]['value'], $field);
- }
- if ($field['type'] == 'it_phone') {
- $node_field[0]['value'] = format_phone_number('it', $node_field[0]['value'], $field);
- }
- if ($field['type'] == 'ca_phone') {
- $node_field[0]['value'] = format_phone_number('ca', $node_field[0]['value'], $field);
- }
- if ($field['type'] == 'uk_phone') {
- $node_field[0]['value'] = format_phone_number('uk', $node_field[0]['value'], $field);
- }
- if ($field['type'] == 'ru_phone') {
- $node_field[0]['value'] = format_phone_number('ru', $node_field[0]['value'], $field);
- } }
- }
- }
- break;
+ if (is_array($node_field)) {
+ foreach ($node_field as $delta => $item) {
+ //format the phone number
+ if ($item['value'] != '') {
+ list($lang) = explode('_', $field['type']);
+ $node_field[0]['value'] = format_phone_number($lang, $node_field[0]['value'], $field);
+ }
+ }
+ }
+ break;
case 'validate':
if (is_array($node_field)) {
- foreach ($node_field as $delta => $item) {
-
- if ($item['value'] != '')
- {
- if ($field['type'] == 'fr_phone' && !valid_phone_number('fr', $item['value'])) {
- form_set_error($field['field_name'],t('"%value" is not a valid French phone number
French phone numbers should only contain numbers and spaces and be like 99 99 99 99 99', array('%value' => $item['value'])));
- }
- if ($field['type'] == 'it_phone' && !valid_phone_number('it', $item['value'])) {
- form_set_error($field['field_name'],t('"%value" is not a valid Italian phone number
Italian phone numbers should only ...', array('%value' => $item['value'])));
- }
- if ($field['type'] == 'ca_phone' && !valid_phone_number('ca', $item['value'])) {
- form_set_error($field['field_name'],t('"%value" is not a valid North American phone number
North American Phone numbers should only contain numbers and + and - and ( and ) and spaces and be like 999-999-9999. Please enter a valid ten-digit phone number with optional extension.', array('%value' => $item['value'])));
- }
- if ($field['type'] == 'uk_phone' && !valid_phone_number('uk', $item['value'])) {
- form_set_error($field['field_name'],t('"%value" is not a valid British phone number
British Phone numbers should .... ', array('%value' => $item['value'])));
- }
- if ($field['type'] == 'ru_phone' && !valid_phone_number('ru', $item['value'])) {
- form_set_error($field['field_name'],t('"%value" is not a valid Russian phone number
British Phone numbers should .... ', array('%value' => $item['value'])));
- } }
+ foreach ($node_field as $delta => $item) {
+ if ($item['value'] != '') {
+ if ($field['type'] == 'fr_phone' && !valid_phone_number('fr', $item['value'])) {
+ form_set_error($field['field_name'],t('"%value" is not a valid French phone number
French phone numbers should only contain numbers and spaces and be like 99 99 99 99 99', array('%value' => $item['value'])));
+ }
+ elseif ($field['type'] == 'it_phone' && !valid_phone_number('it', $item['value'])) {
+ form_set_error($field['field_name'],t('"%value" is not a valid Italian phone number
Italian phone numbers should only ...', array('%value' => $item['value'])));
+ }
+ elseif ($field['type'] == 'ca_phone' && !valid_phone_number('ca', $item['value'])) {
+ form_set_error($field['field_name'],t('"%value" is not a valid North American phone number
North American Phone numbers should only contain numbers and + and - and ( and ) and spaces and be like 999-999-9999. Please enter a valid ten-digit phone number with optional extension.', array('%value' => $item['value'])));
+ }
+ elseif ($field['type'] == 'uk_phone' && !valid_phone_number('uk', $item['value'])) {
+ form_set_error($field['field_name'],t('"%value" is not a valid British phone number', array('%value' => $item['value'])));
+ }
+ elseif ($field['type'] == 'ru_phone' && !valid_phone_number('ru', $item['value'])) {
+ form_set_error($field['field_name'],t('"%value" is not a valid Russian phone number', array('%value' => $item['value'])));
+ }
+ elseif ($field['type'] == 'int_phone' && !valid_phone_number('int', $item['value'])) {
+ form_set_error($field['field_name'],t('"%value" is not a valid international phone number
International phone numbers should contain a country code prefixed by a plus sign followed by the local number.', array('%value' => $item['value'])));
+ }
}
- }
+ }
+ }
break;
- }
+ }
}
/**
@@ -246,7 +244,8 @@
|| $countrycode == 'it'
|| $countrycode == 'ca'
|| $countrycode == 'uk'
- || $countrycode == 'ru') {
+ || $countrycode == 'ru'
+ || $countrycode == 'int') {
//drupal_set_message('langue = ' . $countrycode, 'error');
@@ -282,7 +281,8 @@
|| $countrycode == 'it'
|| $countrycode == 'ca'
|| $countrycode == 'uk'
- || $countrycode == 'ru') {
+ || $countrycode == 'ru'
+ || $countrycode == 'int') {
//drupal_set_message('langue = ' . $countrycode, 'error');
Index: tests/phone.int.test
===================================================================
RCS file: tests/phone.int.test
diff -N tests/phone.int.test
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/phone.int.test 21 Jan 2008 22:53:48 -0000
@@ -0,0 +1,68 @@
+ t('International phone number test'),
+ 'desc' => t('Tests international phone number validation.'),
+ 'group' => t('Phone module'),
+ );
+ }
+
+ function assertConversion($input, $expect = true, $field = array()) {
+ if ($expect === false) {
+ $this->assertFalse(valid_int_phone_number($input, $field));
+ return;
+ } else if ($expect === true) {
+ $expect = $input;
+ }
+ $this->assertTrue(valid_int_phone_number($input, $field));
+ $result = format_int_phone_number($input, $field);
+ $this->assertIdentical($result, $expect);
+ }
+
+ function testBasic() {
+ $this->assertConversion('+1 7329018493');
+ }
+
+ function testBasicWithThreeCountryCode() {
+ $this->assertConversion('+672 565434');
+ }
+
+ function testBasicWithFourCountryCode() {
+ $this->assertConversion('+6724 565434', false);
+ }
+
+ function testBasicWithSpaces() {
+ $this->assertConversion('+1 732 901 8493');
+ }
+
+ function testBasicNormalizeOtherCharacters() {
+ $this->assertConversion('+1 (732) 901-8493', '+1 732 901 8493');
+ }
+
+ function testRemoveNDD() {
+ $this->assertConversion('+54 0435344', '+54 435344');
+ }
+
+ function testRemoveNonStandardNDD() {
+ $this->assertConversion('+374 (8) 435344', '+374 435344');
+ }
+
+ function testAddCountryCode() {
+ $this->assertConversion('732 343 2333', '+1 732 343 2333', array('phone_default_country_code' => '1'));
+ }
+
+ function testOverlongNumber() {
+ $this->assertConversion('+123 456 789 012 3456', false);
+ }
+
+ function testOverlongNumberWithoutCountryCode() {
+ $this->assertConversion('456 789 012 3456', false, array('phone_default_country_code' => '123'));
+ }
+
+}