Апр 29

Апр 28

Во многих веб приложениях необходимо хранить разнообразные настройки. Например, настройки почтовых рассылок в социальных сетях или на форуме. С точки зрения хранения данных одним из распространенных способов является сохранение настроек в поле типа SET. Такой способ удобен для хранения двух состояний каждой настройки (включено/выключено). Но в некоторых случаях нужно сохранять несколько значений. Пример из социальных сетей: настройка приватности “Кто может видеть мой email?” - здесь возможны варианты:

  • все (2)
  • только мои друзья (1)
  • никто (0)

В данном случае настройки можно хранить в виде строки чисел, где каждый символ отвечает за определенный пункт настроек. Например строка “019910” - в ней первый символ отвечает за настройку “Кто может видеть мой email?”. В данном примере первый символ равен “0″, т.е. никто не может видеть email пользователя.

Ну вот, хотел написать об MySQL функции, а получилось вступление по другой теме :-)

Перейдем к примерам работы со строками в MySQL.

MySQL предоставляет целый ряд функций для работы со строками. Для замены символа (или подстроки) используется функция INSERT:

INSERT(str, pos, len, newstr) - возвращает строку str, где подстрока, которая начинается с pos и имеет длину len, заменена строкой newstr

Пример:

SELECT INSERT(’Zend Framework’, 1, 4, ‘Symfony’)

Такой запрос заменяет подстроку “Zend” на “Symfony” и в результате получается “Symfony Framework”.

Очень важно помнить, что в MySQL индексы строк начинаются с 1, а не с 0!

Таким образом, для замены символа в строке (на примере настроек приватности):

UPDATE `users` SET `privacy` = INSERT(`privacy`, 1, 1, ‘2′)

Данным запросом меням настройку приватности для email. Исходная строка принимает значение “219910″ - это значит что email доступен для просмотра всем.

Кажется, пора идти домой уже… :-)

Апр 15

Очень удобная вещь - Zend_Form. Данный компонент предоставляет множество возможностей, таких как фильтрация и валидация данных формы. Zend_Form имеет ряд собственных валидаторов и фильтров, но он достаточно гибок, и есть возможность создавать свои классы для валидации.

Рассмотрим на примере создание собственного валидатора для формы регистрации.

Возьмем простейшую форму для регистрации, с минимальным набором полей:

  • логин
  • email
  • пароль
  • пароль повторно

Требования к полям:

  1. Логин - обязательное поле, строка из цифро-буквенных символов длиною от 3 до 15 символов, уникальное.
  2. email - обязательное поле, имеет правильный формат, уникальное.
  3. Пароль - обязательное поле, строка из любых символов, не короче 6 символов
  4. Пароль повторно - поле должно совпадать с полем ‘пароль’.

Исходя их требований, можно сделать вывод, что нам нужно написать 3 собственных валидатора:

  1. Проверка уникальности логина.
  2. Проверка уникальности email.
  3. Проверка совпадения паролей.

Для создания custom validator, нужно наследовать класс от абстрактного Zend_Validate_Abstract, и реализовать в нем метод isValid.

В своих проектах валидаторы я храню в директории models/validator.

Создание валидатора уникальности логина

Создаем новый файл models/validator/UniqueNickname.php

<?php
class Validator_UniqueNickname extends Zend_Validate_Abstract
{
    const NOT_UNIQUE = ‘notUnique’;
    
    /*
     * Сообщения об ошибках валидации
     */
    protected $_messageTemplates = array(
        self::NOT_UNIQUE => “Username ‘%value%’ has already been taken”
    );
    
    public function isValid($value)
    {
        $this->_setValue($value);
        $isValid = true;
        
        /*
         * Метод User::checkLogin проверяет используется ли в базе такой логин,
         * если да, то возвращает user id
         */  
        $userId = User::checkLogin($value);
        if ($userId) {
            $this->_error(self::NOT_UNIQUE);
            $isValid = false;
        }
        return $isValid;
    }
}

Создание валидатора уникальности email

Создаем новый файл models/validator/UniqueEmail.php

<?php
class Validator_UniqueEmail extends Zend_Validate_Abstract
{
    const NOT_UNIQUE = ‘notUnique’;
    
    protected $_messageTemplates = array(
        self::NOT_UNIQUE => “Email ‘%value%’ has already been taken”
    );
    
    public function isValid($value)
    {
        $this->_setValue($value);
        $isValid = true;
        $userId = User::checkEmail($value);
        if ($userId) {
            $this->_error(self::NOT_UNIQUE);
            $isValid = false;
        }
        return $isValid;
    }
}

Создание валидатора для паролей

С этим валидатором дела обстоят интереснее. Создаем новый файл models/validator/EqualValues.php.

<?php
class Validator_EqualValues extends Zend_Validate_Abstract
{
    const NOT_EQUAL = ‘notEqual’;
    
    protected $_messageTemplates = array(
        self::NOT_EQUAL => ‘Passwords are not equal’
    );
    
    protected $_contextKey;
    
    public function __construct($key)
    {
        $this->_contextKey = $key;
    }
    
    public function isValid($value, $context = null)
    {
        if (is_array($context)) {
            if (isset($context[$this->_contextKey]) && ($value === $context[$this->_contextKey])) {
                return true;
            }
        }
        if ($value === $context) {
            return true;
        }
        $this->_error(self::NOT_EQUAL);
        return false;
    }
}

Форма регистрации

Теперь создаем непосредственно саму форму регистрации (models/form/Register.php)

<?php
class Form_Register extends Zend_Form
{
    public function __construct($options = null)
    {
        parent::__construct($options);
        
        $this->setAction(HOME_URL . ‘register/’)
             ->setMethod(‘post’);
        
        $login = new Zend_Form_Element_Text(‘login’);
        $login->setLabel(‘Логин’)
              ->setRequired(true)
              ->addFilter(‘StripTags’)
              ->addFilter(‘StringTrim’)
              ->addFilter(‘StringToLower’)
              ->addValidator(‘StringLength’, true, array(‘min’ => 3, ‘max’ => 15))
              ->addValidator(‘alnum’)
              ->addValidator(new Validator_UniqueNickname())
              ;
              
        $email = new Zend_Form_Element_Text(‘email’);
        $email->setLabel(‘email’)
              ->setRequired(true)
              ->addFilter(‘StripTags’)
              ->addFilter(‘StringTrim’)
              ->addFilter(‘StringToLower’)
              ->addValidator(new Zend_Validate_EmailAddress())
              ->addValidator(new Validator_UniqueEmail())
              ;
        
        $password = new Zend_Form_Element_Password(‘password’);
        $password->setLabel(‘Пароль’)
                 ->setRequired(true)
                 ->addValidator(‘StringLength’, true, array(‘min’ => 6))
                 ;
        
        $passwordAgain = new Zend_Form_Element_Password(‘passwordAgain’);
        $passwordAgain->setLabel(‘Повторите пароль’);
        
        // Валидатор для совпадения паролей 
        $passwordAgain->addValidator(new Validator_EqualValues(‘password’))
                      ->setAllowEmpty(false);
        
        $submit = new Zend_Form_Element_Submit(’submit’);
        $submit->setLabel(‘Ok’);
        
        $this->addElements(array($login, $email, $password, $passwordAgain, $submit));
    }
}

При добавлении валидатора для паролей нужно вызывать метод setAllowEmpty со значением false. Это делается для того чтобы валидатор паролей срабатывал при пустом значении “Пароль повторно”.

Сам процесс регистрации не входит в рамки данной статьи, возможно позже напишу продолжение данной статьи.