Version: current

      1 <?php
      2 /**
      3  * Свое поле для телефонов с валидацией
      4  *
      5  *
      6  */
      7 class PhoneField extends TextField {
      8
      9     protected static $fixed_part = '';
     10
     11     /**
     12      * Устаналивает фиксированную часть номера для всех полей PhoneField на сайте
     13      *
     14      * @param string $part
     15      */
     16     static function set_fixed_part($part) {
     17         self::$fixed_part = $part;
     18     }
     19
     20     protected static $max_length = 15; // по стандарту E164
     21
     22     /**
     23      * Устаналивает максимальную длину номера для всех полей PhoneField на сайте
     24      *
     25      * @param int $val
     26      */
     27     static function set_max_length($val) {
     28         self::$max_length = $val;
     29     }
     30
     31     protected static $min_length = 3; // если только локальный
     32
     33     /**
     34      * Устаналивает минимальную длину номера для всех полей PhoneField на сайте
     35      *
     36      * @param int $val
     37      */
     38     static function set_min_length($val) {
     39         self::$min_length = $val;
     40     }
     41
     42     // пока не используем, т.к. все проверяется регуляркой и не дает ввести неправильное
     43     static $value_searches = array(
     44         '/[^\d+]+/', // не цифры и "+" - в топку
     45         //'/^8([^8]\d{9})/', // полный Российский номер на 8 меняем на 7 (кроме 8-800-*)
     46     );
     47
     48     static $value_replaces = array(
     49         '',
     50         //'7$1',
     51     );
     52
     53     /**
     54      * Добавляет замену в список замен
     55      *
     56      * @param string $from
     57      * @param string $to
     58      */
     59     static function add_replace($from, $to) {
     60         self::$value_searches[] = $from;
     61         self::$value_replaces[] = $to;
     62     }
     63
     64     /**
     65      * Заменяет список замен
     66      *
     67      * @param array $from
     68      * @param array $to
     69      */
     70     static function set_replaces($from, $to) {
     71         self::$value_searches = $from;
     72         self::$value_replaces = $to;
     73     }
     74
     75
     76     /**
     77      * Выполняет преобразования телефонного номера
     78      *
     79      * @param string $val - "грязный" номер
     80      *
     81      * @return string - "чистый" номер
     82      */
     83     static function cleanup_phone($val) {
     84         $val = trim($val);
     85         if (count(self::$value_searches) > 0 && count(self::$value_searches) == count(self::$value_replaces)) {
     86             return preg_replace(self::$value_searches, self::$value_replaces, $val); // в принцие, 8 в начале не пройдет валидацию, но возможно пригодится для чего-то еще
     87         }
     88         return $val;
     89     }
     90
     91     // фиксированная часть конкретного поля
     92     protected $fixedPart = false;
     93
     94     // минимальная длина конкретного поля
     95     protected $minLength = false;
     96
     97     function setFixedPart($value) {
     98         $this->fixedPart = $value;
     99         if (!$this->value || ($this->value == self::$fixed_part))
    100             $this->setValue($value);
    101     }
    102
    103     /**
    104      * Возвращает фиксированную часть номера
    105      *
    106      * @return string
    107      */
    108     function getFixedPart() {
    109         if ($this->fixedPart !== false) {
    110             return $this->fixedPart;
    111         }
    112         return self::$fixed_part;
    113     }
    114
    115     function setMinLength($val) {
    116         $this->minLength = $val;
    117     }
    118
    119     function getMinLength() {
    120         if ($this->minLength !== false) {
    121             return $this->minLength;
    122         }
    123         return self::$min_length;
    124     }
    125
    126     function __construct($name, $title = null, $value = "", $maxLength = null, $form = null){
    127         if (!$value) {
    128             $value = $this->getFixedPart();
    129         }
    130         if (!$maxLength) {
    131             $maxLength = self::$max_length;
    132         }
    133
    134         $this->setHTML5Attribute('type', 'tel');
    135         $this->setAutocomplete('tel');
    136
    137         parent::__construct($name, $title, $value, $maxLength, $form);
    138
    139         $pattern = $this->getValidationRegexp();
    140         $this->setFieldPattern($pattern);
    141     }
    142
    143     function setFieldPattern($pattern) {
    144         // выкидываем лидирующий и финишный / для атрибута pattern
    145         $pattern = preg_replace("/^\//", "", $pattern);
    146         $pattern = preg_replace("/\/$/", "", $pattern);
    147         $this->setHTML5Attribute('pattern', $pattern);
    148     }
    149
    150     function getFieldPattern($withSlashes=false) {
    151         $pattern = $this->getHTML5Attribute('pattern');
    152         return ($withSlashes ? "/{$pattern}/" : $pattern);
    153     }
    154
    155     /**
    156      * Формирует regexp для валидации номера
    157      *
    158      * @return string
    159      */
    160     function getValidationRegexp() {
    161         $max = $this->getMaxLength() - strlen($this->getFixedPart());
    162         $min = max($this->getMinLength() - strlen($this->getFixedPart()), 0);
    163         $min = min($min, $max);
    164         return sprintf("/^\+?%s\d{%d,%d}$/", preg_quote(str_replace('+','', $this->getFixedPart())), $min, $max);
    165     }
    166
    167     function jsValidation() {
    168         $formID = $this->form->FormName();
    169         $error = _t('PhoneField.VALIDATIONJS', 'Please enter correct phone.');
    170         $regexp = $this->getFieldPattern(true);
    171
    172         $jsFunc =<<<JS
    173 Behaviour.register({
    174     "#$formID": {
    175         validatePhoneField: function(fieldName) {
    176             var el = _CURRENT_FORM.elements[fieldName];
    177             if(!el || !el.value) return true;
    178             var val = el.value.replace(/[^0-9+]+/g, '');
    179             if(val.match({$regexp})) {
    180                 return true;
    181             } else {
    182                 validationError(el, "$error","validation");
    183                 return false;
    184             }
    185         }
    186     }
    187 });
    188 JS;
    189         //fix for the problem with more than one form on a page.
    190         Requirements::customScript($jsFunc, 'func_validatePhoneField' .'_' . $formID);
    191
    192         return <<<JS
    193 if(typeof fromAnOnBlur != 'undefined'){
    194     if(fromAnOnBlur.name == '$this-me')
    195         $('$formID').validatePhoneField('$this-me');
    196 }else{
    197     $('$formID').validatePhoneField('$this->name');
    198 }
    199 JS;
    200     }
    201
    202     function validate($validator){
    203         if ($this->value && !preg_match($this->getFieldPattern(true), $this->value)){
    204             if ($validator) {
    205                 $validator->validationError(
    206                     $this->name,
    207                     _t('PhoneField.VALIDATION', "Please enter correct phone."),
    208                     "validation"
    209                 );
    210             }
    211             return false;
    212         } else {
    213             return parent::validate($validator);
    214         }
    215     }
    216
    217     /**
    218      * Подготоваливает данные к записи в БД
    219      * Производит необходимые замены в номере
    220      *
    221      * @return string
    222      */
    223     function dataValue() {
    224         return self::cleanup_phone($this->value);
    225     }
    226 }
    227

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -