Как стать автором
Обновить

Создание формы с асинхронной валидацией на сервере в Joomla 1.5

Время на прочтение 6 мин
Количество просмотров 915
В этой статье я покажу один из путей создания в Joomla 1.5 формы с асинхронной валидацией на сервере. Для этого мы создадим компонент, построенный в соответствие с концепцией MVC, реализованной в Joomla 1.5, в качестве JS-фреймворка будет использоваться mootools 1.2.



Введение


В этой статье я не буду углубляться в теорию концепции MVC и ее реализацию в Joomla 1.5. Также я предполагаю, что читатель знаком с общим принципом создания компонентов для этой CMS, если же нет, то можно посмотреть, например, вот это. Возможно, я когда-нибудь напишу статью и об этом, но сейчас мне бы хотелось осветить сабж :)

Постановка задачи


Требуется создать frontend-компонент, который бы реализовывал асинхронную валидацию на сервере введенных в форму данных. Для осуществления асинхронного обращения к серверу мы будем использовать mootools 1.2.x В Joomla 1.5 уже встроен mootools 1.1, однако, просто подменить файлы с кодом не получится – Joomla станет плохо работать. Но как всегда, хочется использовать современные решения, поэтому, мы не будем задействовать доступный в Joomlа mootools, а подключим свой, последней версии. Конечно, существует риск возникновения конфликных ситуаций, но будем считать, что на фронтенде у нас не будет компонентов, использующих встроенный mootools :) Кроме того, данный способ будет полезен тем, кто хочет использовать какой-нибудь другой JS-фреймворк.

Реализация


Схема работы нашего компонента будет следующей. При нажатии на кнопку отправки (submit) формы, данные из полей будут асинхронно отправляться на сервер, где их будет «принимать» Контроллер, проверять данные и возвращать ответ в формате JSON, в котором будет содержаться информация о валидности введенных данных. Эта информация будет использоваться на клиенте для отображения с помощью CSS результатов проверки.

Перед тем, как перейти непосредственно к коду, необходимо сделать кое-какие пояснения. Согласно концепции MVC все запросы пользователя к компоненту должны обслуживаться Контроллером (Controller). Получив команду, контроллер «решает», как на эту команду реагировать. В классической схеме Контроллером дается команда Модели (Model) для получения/сохранения/обновления данных, а результат этой команды отображается Видом (View), который «знает» как отобразить данные.

В нашем простейшем компоненте Модели не будет, поэтому соответствующий класс будет пустой, он присутствует в этом примере только с целью демонстрации общей организации кода компонента. Задача Вида – включить необходимые стили и скрипты, и вывести форму. В Контроллере же будет реализована функциональность валидации формы на сервере в виде отдельной задачи (task), которую мы будем вызывать асинхронно.

В папке фронтенд-части нашего компонента (который мы назовем AsyncForm), т.е. в папке /components/com_asyncform у нас будет следующая структура папок и файлов:

+com_asyncform
   +assets
      +css
         -common.css
      +js
         -common.js
         -mootools-1.2.1-core.js
   +controllers
      -default.php
   +models
      -asyncform.php
   +views
      +tmpl
         -default.php
      -view.html.php
   -asyncform.php


asyncform.php

  1. <?php
  2. defined( '_JEXEC' ) or die( 'Restricted access' );

  3. if($controller = JRequest::getVar('controller')) {
  4.   require_once(JPATH_COMPONENT.DS . 'controllers' . DS . $controller . '.php');
  5.   require_once(JPATH_COMPONENT.DS . 'models' . DS . 'asyncform.php');
  6.   require_once(JPATH_COMPONENT.DS . 'views' . DS . $controller . DS . 'view.html.php');
  7. }
  8. else {
  9.   require_once(JPATH_COMPONENT.DS . 'controllers' . DS . 'default.php');
  10.   require_once(JPATH_COMPONENT.DS . 'models' . DS . 'asyncform.php');
  11.   require_once(JPATH_COMPONENT.DS . 'views' . DS . 'default' . DS . 'view.html.php');
  12. }

  13. // Create the controller
  14. $classname  = 'AsyncformController'.$controller;

  15. $controller = new $classname;
  16. $controller->execute(JRequest::getVar('task'));
  17. $controller->redirect();
  18. ?>



controllers/default.php

  1. <?php
  2. jimport( 'joomla.application.component.controller' );

  3. class AsyncformController extends JController {
  4.   function __construct($default = array()) {
  5.     parent::__construct($default);
  6.     $this->registerDefaultTask('display');
  7.     $this->registerTask('check', 'check');
  8.   }

  9.   function cancel() {
  10.     $this->setRedirect('index.php');
  11.   }
  12.        
  13.   function display() {
  14.     $view = new AsyncformView();
  15.     $view->display();
  16.   }

  17.   function check() {
  18.     $isValid = false;
  19.     $res['type'] = '';
  20.     $res['msg'] = '';
  21.     $res['items'] = array();

  22.     $name = substr(JRequest::getVar('name'), 0, 50);
  23.     if(ereg('[а-яА-Яa-zA-Z\-]+$', $name)) {
  24.       $res['items'][] = array('name' => 'name', 'status' => 1);
  25.       $isValid = true;
  26.     }
  27.     else {
  28.       $res['items'][] = array('name' => 'name', 'status' => 0);
  29.       $isValid = false;
  30.     }

  31.     $email = strtolower(substr(JRequest::getVar('email'), 0, 50));
  32.     if(ereg('^[^0-9][a-z0-9_\-\.]+@[^0-9][a-z\-\.]+\.[a-z]{2,4}$', $email)) {
  33.       $res['items'][] = array('name' => 'email', 'status' => 1);
  34.       $isValid = true;
  35.     }
  36.     else {
  37.       $res['items'][] = array('name' => 'email', 'status' => 0);
  38.       $isValid = false;
  39.     }    
  40.         if($isValid) {
  41.       $res['type'] = 'valid';
  42.       $res['msg'] = 'Форма заполнена правильно';
  43.     }
  44.     else {
  45.       $res['type'] = 'error';
  46.       $res['msg'] = 'Ошибка!';
  47.     }

  48.     echo json_encode($res);
  49.   }
  50. }
  51. ?>


В методе check() формируется ответ в формате JSON, который состоит из:
  • текстового поля type — результат проверки (valid или error)
  • текстового поля msg — сообщение для пользователя
  • массива items, элементами которого являются массивы из двух элементов, в которых хранится id поля формы и их статус, эта информация нам понадобится, чтобы отображать, в каких полях ошибка


models/asyncform.php

  1. <?php
  2. jimport( 'joomla.application.component.model' );

  3. class AsyncformModel extends JModel {
  4. }
  5. ?>



views/default/view.html.php

  1. <?php
  2. jimport( 'joomla.application.component.view' );

  3. class AsyncformView extends JView {
  4.   public $message;

  5.   function __construct() {
  6.     $this->addTemplatePath(JPATH_COMPONENT . DS . 'views' . DS . 'default' . DS . 'tmpl');
  7.   }

  8.   function display($tpl = null) {
  9. //  JHTML::_('behavior.mootools');

  10.     $document = &JFactory::getDocument();
  11.     $document->addStyleSheet('components/com_asyncform/assets/css/common.css');
  12.     $document->addScript('components/com_asyncform/assets/js/mootools-1.2.1-core.js');
  13.     $document->addScript('components/com_asyncform/assets/js/common.js');

  14.     parent::display($tpl);
  15.   }
  16. }
  17. ?>


Если все таки хочется использовать встроенный mootools, тогда используйте оператор в строке 12 вместо строки 16.

views/default/tmpl/default.php

  1. <?php defined('_JEXEC') or die('Доступ запрещен'); ?>

  2. <div id="log"></div>

  3. <form id="frm_asyncform" action="index.php?option=com_asyncform&task=check&format=raw" method="post">
  4.   <table>
  5.     <tr>
  6.       <td>Имя</td>
  7.       <td><input type="text" name="name" id="name" /></td>
  8.     </tr>
  9.     <tr>
  10.       <td>E-mail</td>
  11.       <td><input type="text" name="email" id="email" /></td>
  12.     </tr>
  13.   </table>
  14.   <input type="submit" name="btn_submit" id="btn_submit" value="Отправить" />
  15. </form>


Обратите внимание на обработчик формы. Такой вид обработчика обусловлен тем, что от сервера нам надо получить лишь строку ответа, без всякой дополнительной html-разметки и т.п. В Joomla 1.0.x для того чтобы вернуть только вывод компонента, надо было использовать index2.php, однако в Joomla 1.5 это не пройдет. Для этих целей в ней предусмотрен параметр format, который для того, чтобы вернуть только вывод компонента, должен быть равен raw.

assets/css/common.css

  1. .error {
  2.   border: 2px solid #ff0000;
  3. }

  4. #log {
  5.   padding: 5px;
  6.   overflow: auto;
  7.   margin-bottom: 5px;
  8.   width: 452px;
  9. }

  10. #log.loaded {
  11.   background-color: #ffc0c0;
  12. }

  13. #log.loaded-success {
  14.   background-color: #c0ffc0;
  15. }



assets/js/common.js

  1. window.addEvent('domready', function() {
  2.   $('frm_asyncform').addEvent('submit', function(e) {
  3.     e.stop();
  4.     var log = $('log').empty();
  5.     this.set('send', {
  6.       method: 'post',
  7.       onComplete: function(response) {
  8.         var res = JSON.decode(response);
  9.         res.items.each(function(field) {
  10.           if(field.status)
  11.             $(field.name).removeClass('error');
  12.           else
  13.             $(field.name).addClass('error');
  14.         });
  15.         if(res.type == 'valid')
  16.           log.addClass('loaded-success');
  17.         else
  18.           log.addClass('loaded');
  19.         log.set('html', res.msg);
  20.       }
  21.     });
  22.     this.send();
  23.   });
  24. });


Здесь ответ, полученный от сервера в виде строки преобразуется в js-объект, после чего анализируется его содержимое и выставляются нужные параметры html-элементам в теле компонента.

Вот, собственно, и все. Надеюсь, данный пост будет кому-нибудь полезен. Комменты, советы и предложения, естественно, приветствуются!
Теги:
Хабы:
+6
Комментарии 6
Комментарии Комментарии 6

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн