Pull to refresh

Декоратор для обработки форм Ajax`ом

Lumber room
После прочтения статьи я решил написать декоратор который будет прикреплять jquery код для получения данных из формы и отправки их на сервер.
Своим опытом спешу поделится с хабрасообществом.

То как создавать декораторы и о формах в модели замечательно описывается в статье ссылку на которую я привёл выше, так что заострять на этом внимание я не буду.
Итак нам нужно чтобы получилось нето следуещее:

<from ...>
<input ...>
<div id="error_...">
Сюда будем выводить сообщение о том что поле не прошло валидацию
</div>
</form>
<div id ="">
Сюда мы будем выводить ответ от сервера
<div>
<script>
Здесь код для обработки формы
</script>



Решение элементарно:
class App_Form_Decorator_Ajax extends Zend_Form_Decorator_Abstract  
{
    public function getJSCode()
    {
        $form = $this->getElement(); 
        $button = $form->getElement('submit');
        $jsCode='
		<div id ="check'.$form->getAttrib('id').'"></div>        		
		<script>
		    $("#'.$button->getAttrib('id').'").click(function () {      
		   	data =	$("#'.$form->getAttrib('id').'").serialize();      
		       $.ajax({													
				   type: "'.$form->getMethod().'",					
				   url: "'.$form->getAction().'",					
				   data: data,										
				   success: function(msg){
				     $("#check'.$form->getAttrib('id').'").html(msg)  
				   }
				 });
		      return false;
		 });
		 </script>
		';
		return $jsCode;
	}
	
	public function render($content)
	{
                 $element = $this->getElement();
                 if (null === $element->getView()){
                 return $content;
            }
		 $placement = $this->getPlacement();
		 switch  ($placement) {
            case  'APPEND':
                return $content.$this->getJSCode();
            case  'PREPEND':
                return  $this->getJSCode().$content;
            case  null:
            default:
                return $content.$this->getJSCode();
		}
	}
}


у нас есть 2 метода
getJSCode() — генерирует jquery код для формы в зависимости от того какие параметры существуют в форме, а именно нам нужны action и method этой формы, а так же id кнопки submit и id самой формы для получения из неё параметров.
Ещё нам понадобиться div для того чтобы возвращать в него ответ сервера.
Получаем экземпляр класса формы из него получаем элемент submit далее составляем код в который добавлен div для того чтобы записывать в него ответы от сервера.
В jquery для обработчика click возвращаем false иначе при нажатии на кнопку пользователь будет попадать на страницу с заданным action.
Осталось реализовать стандартный метод render который предоставляет нам Zend_Form_Decorator_Abstract, там всё достаточно просто взависимости от опций декоратора возвращаем jquery код на нужном месте.

Затем нам нужен декоратор для элемента формы он будет дописывать див к кэлементу в который будем писать сообщение о том что данные из этой формы не прошли валидацию.
class App_Form_Decorator_AjaxErrors extends Zend_Form_Decorator_Abstract  
{
	public function _getHtmlCode()
	{
		$element = $this->getElement();
		$HtmlCode='
		<div id="error_' . $element->getName() . '"></div>
		';
		return $HtmlCode;
	}
	
	public function render($content)
	{
        $element = $this->getElement();
        if (!$element instanceof Zend_Form_Element) {
            return $content;
        }
        if (null === $element->getView()) {
            return $content;
        }
        $placement = $this->getPlacement();
		switch  ($placement) {
            case  'APPEND':
                return $content.$this->_getHtmlCode();
            case  'PREPEND':
                return  $this->_getHtmlCode().$content;
            case  null:
            default:
                return $content.$this->_getHtmlCode();
		}
	}
}



здесь всё аналагично предыдущему декоратору только вместо JSкода мы вставяем код с нашим дивом у которого id =«error_<имя элемента формы>»

Нам нужно будет создать сообщение о том что валидация не увенчалась успехом

class App_Form extends Zend_Form 
{  
    public function init()
    {
        // Вызов родительского метода
        parent::init();
        
        // Создаем объект переводчика, он нам необходим для перевода сообщений об ошибках.
        // В качестве адаптера используется php массив
        $translator = new Zend_Translate('array',  './application/translate/errors.php');
        
        // Задаем объект переводчика для формы
        $this->setTranslator($translator);
        
        /* Задаем префиксы для самописных элементов, валидаторов, фильтров и декораторов.
           Благодаря этому Zend_Form будет знать где искать наши самописные элементы */
       $this->addElementPrefixPath('App_Validate', 'App/Validate/', 'validate');
       $this->addElementPrefixPath('App_Filter', 'App/Filter/', 'filter');
       $this->addElementPrefixPath('App_Form_Decorator', 'App/Form/Decorator/', 'decorator');
    }
     public  function printErrorMessages()
     {
        echo '<script>';
            foreach ($this->getElements() as $element){                   
                $errors = '';
                foreach ($element->getMessages() as $error){          
                    $errors.= $error . "<br>";             
                }
                echo '$("#error_' . $element->getName() . '").html("' . $errors . '");';
            }
        echo '</script>';
      }
}



Здесь мы немного расширяем класс Zend_Form дописывая туда пути для валидаторов декораторов и фильтров а так же устанавливая файл с переведёнными ошибками на русский язык.
Метод printErrorMessages() выводит для каждого элемента код который вставляет в нужный див сообщение о ошибке, если таковая имееться.

Нам понадобится форма описанная например вот так:

class Form_Comment extends App_Form  
{
    public $action = '/index/add/';
    public function init()
   {
            parent::init();
	$helper  = new Zend_View_Helper_Url();
	$this->setMethod('POST');
	$this->setAction('/index/add/');
	$this->setAttrib('id','commentform');		
	$login = new Zend_Form_Element_Text(
	'login',
	array(
		'label'=> 'Имя',
		'required'    => true,
		'filters'     => array('StringTrim')
	));
	$login->addDecorator('AjaxErrors');
	$this->addElement($login);
	$message = new Zend_Form_Element_Textarea(
	'message',
	array(
		'label'=> 'Cooбщение',
		'required'    => true
	));
	$message->addDecorator('AjaxErrors');
	$this->addElement($message);	
            $submit = new Zend_Form_Element_Submit('submit', array(
            'label'       => 'Добавить комментарий',
            'id'=>'qwer'
        ));
        $this->addElement($submit);
    }
}



это простая форма добавления комметария, здесь помимо всего прочего мы устанавливаем декоратор AjaxError для нужных нам полей
$login->addDecorator('AjaxErrors');

Ну и последнее это использование.

У нас есть 2 события первое это в котором выводится сама форма, а во второе мы будет отсылать данные.

function indexAction()
    {
        $commentForm = new Form_Comment();
        $this->view->commentForm = $commentForm;
        $commentForm->addDecorator(new App_Form_Decorator_Ajax());
    }



Создаём форму привязываем к ней декоратор и отправляем в вид, в виде стоит незабыть подключить jquery.

    function addAction()
    {
        $commentForm = new Form_Comment();
        if($this->getRequest()->isXmlHttpRequest()){
        if ($this->_request->isPost()) { 
            if ($commentForm->isValid($this->_getAllParams())) { 
                echo $commentForm->getValue('login')."<br>";
                echo $commentForm->getValue('message');
            }else {
               $commentForm->printErrorMessages();
            }
        }
    } else {
              echo "Включите пожалуйста javascript в вашем браузере";
    }
}



Здесь мы снова создаём нашу форму, затем проверяем каков запрос если он передан Ajax`ом значит JS у пользователя в браузере включён, тогда двигаемся дальше, иначе выкидываем сообщение с советом включить JS. Затем если произошел POST и значения в форме валидны делаем что-то например заносим сообщение в бд.

Многие могут сказать что это куча ненужного кода, будет уменьшаться производительность скриптов, но на практике это очень сильно экономит время, нам не приходится много раз переписывать один и тот же код, нам нужно будет только создать форму и прекрепить к ней декоратор и ajax готов :)
Надеюсь что это пригодится кому то и избавит от рутины.
Tags: phpzend frameworkzend_formajaxjquery
Hubs: Lumber room
Total votes 9: ↑8 and ↓1 +7
Comments 2
Comments Comments 2

Popular right now