MODX - FormIt

FormIt - это как бы аналог eForm(MODX Evo). Но намного круче и удобнее. Я не буду тут описывать то, что есть в официальной документации. Затрону только молоизвестные и недокументированные возможности. В отличие от eForm сама форма распологается сразу после сниппета. Не в чанках.

Я в последнее время пишу через API. Оказалось это удобнее не только в части эффективности кода, но и в организации тех же шаблонов, скриптов и прочих связанных модулей. Ну об этом в другой раз. Короче все шаблоны к сниппетам (tpl - файлы) я стараюсь хранить как файлы в тех же каталогах, где лежат сниппеты и прочие относящиеся к конкретному блоку. Иначе приходится порой часами собирать все куски, ползая по админке. И поэтому для меня важна возможность загрузки в сниппеты TPL как файлов. Прочитав доки по FormIt я не обнаружил такой возможности. Там хуки грузятся как сниппеты, шаблоны - как чанки. Естественно как-то расстроился. Но как-то не верилось, что столь крутой автор мог так со мной поступить). Полез в исходники и радости не было предела. В частности для EMAIL можно тремя способами грузить шаблоны:

  1. Как чанки, просто указав имя чанка:
            &emailTpl=`MyEmailChunk`
            
    А FormIt загрузит его так:
                    $chunk = $this->modx->getObject('modChunk',array('name' => $name),true);
            
  2. Как код:
    &emailTpl=`@CODE:<div>......</div>`
  3. Как файл из каталога шаблонов:
    &emailTpl=`myTpl`
            $f = $this->config['chunksPath'].$lowerCaseName.'.chunk.tpl';
            т.е. будет искать файл '/core/components/formit/elements/chunks/myTpl.chunk.tpl'
            
  4. Как путь к файлу:
    &emailTpl=`myDir/myTpl.tpl`
                $o = file_get_contents($f);
                /** @var modChunk $chunk */
                $chunk = $this->modx->newObject('modChunk');
                $chunk->set('name', $name);
                $chunk->setContent($o);
                $chunk->setCacheable(false);
                return $chunk->process($properties);
            
    Т.е. можно указать относительный путь или абсолютный(что порой проблематично). Конечно не очень круто. Нормальные сниппеты требуют пути относительно корня сайта. Ну хоть так.

Хуки - функции обратного вызова. Вызываются после валидации. В EVO в качестве хука вызывается произвольная функция, которую предварительно определяют в сниппете. То здесь, они грузятся как кусок кода(сниппет). Хотя в документации есть намек, что можно загрузить как файл-скрипт. Но я не нашел как это реализовать. Пришлось опять же лезть в исходники.

Здесь 2 варианта.

  1. Просто как имя сниппета
        &preHooks=`loadCustomValues`
        в FormIt:
        $snippet = $this->modx->getObject('modSnippet',array('name' => $hookName))) {
                /* custom snippet hook */
                $properties = array_merge($this->formit->config,$customProperties);
                $properties['formit'] =& $this->formit;
                $properties['hook'] =& $this;
                $properties['fields'] = $this->fields;
                $properties['errors'] =& $this->errors;
                $success = $snippet->process($properties);
      
    
  2. Как файл
    В FormIt:
                $this->modx->parser->processElementTags('',$hookName,true,true); // т.е. можно тэг подсунуть и он пропарсится
                if(file_exists($hookName)) {
                    $success = $this->_loadFileBasedHook($hookName,$customProperties);
                }
                
                далее просто $success = include $path;
    
    И опять же можно или относительные пути задать или абсолютные. Это, конечно, не очень удобно. Но решаемо. Вот нашел в дебрях документации:
      [[!FormIt? 
         &hooks=`[[++assets_path]]hooks/myHook.php`
      ]] 
      я же использовал при ajax 
      [[!FormIt? 
         &hooks=`hooks/myHook.php`
      ]] 
      и хук загружается относительно директория коннектора(каталога скрипта ajax). Но абсолютные пути предпочтительнее. Наверное.
      
               
При этом хуки обрабатываются до обработки шаблона формы, поэтому можно подменить вывод и прервать PHP : exit(); Некоторые полезности в скриптах-хуках(пре-хуках)
$hook->formit->config['key'] - доступ к параметрам скрипта
$hook->setValue('email','john.doe@fake-emails.com'); - установка полей 
$hook->setValue('hobbies',json_encode(array('music','films','books'))); - установка полей с массивом данных(checkbox, select)
$email = $hook->getValue('email'); - доступ у полям 
$allFormFields = $hook->getValues(); - все поля в массив
$hook->setValues(array(
  'name' => 'John Doe',
  'email' => 'john.doe@fake-emails.com',
)); - загрузка через массив
И не забывайте ставить в конце хука return true; или $hook->addError('user','User not found.'); return $hook->hasErrors();

Реализовано на модали Bootstrap:

  1. Вызов модали(на странице).
    <a href="#" data-toggle="modal" data-target="#ModalRequestCall">Заказать звонок</a>  		
            
  2. Mодаль(на странице).
    <div class="modal fade" id="ModalRequestCall" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
            <h4 class="modal-title" id="myModalLabel">Заказать звонок</h4>
          </div>
          <div class="modal-body">
            ...
          </div>
          <div class="modal-footer">
            <p><small>*Отправляя заявку, я соглашаюсь на обработку своих персональных данных, указанных в заявке, с целью информирования меня об услугах организации
            </small>
            </p>
          </div>
        </div>
      </div>
    </div> 		
            
  3. AJAX.
    1. Где-то кладем файл ...../ajFormIt.php
      <?php
      require_once $_SERVER['DOCUMENT_ROOT'].'/manager/config.core.php';
      require_once MODX_CORE_PATH.'model/modx/modx.class.php';
      $modx = new modX();
      $modx->initialize('web');
      
      $out="";
      
      $Tpl=file_get_contents($_SERVER['DOCUMENT_ROOT']."/...../myDir/form.tpl");
      $uniqid = uniqid();
      $chunk = $modx->newObject('modChunk', array('name' => "tmpCnank-{$uniqid}"));
      $chunk->setCacheable(false);
      
      /*
      проинициализируем плейсхолдеры, чтоб попусту не гонять парсер. 
      иначе непропарсенные тэги вылезут на форме. они в данном случае не удаляются/
      */
      $params=array();  
      $params['fi']=array();
      $params['fi']['error']=array();
      $params['fi']['error']['name']='';
      $params['fi']['error']['email']='';
      $params['fi']['error']['phone']='';
      $params['fi']['validation_error_message']='';
      $params['fi']['name']='';
      $params['fi']['email']='';
      $params['fi']['phone']='';
      $params['fi']['successMessage']='';
      
      $out.=$chunk->process($params,$Tpl);
      echo $out;
                          
    2. Делаем файл шаблона - '...../myDir/form.tpl'

      [[FormIt?
         &hooks=`myHook.php`
         &validate=`fio:blank,
            name:required:stripTags,
            email:email,
            phone:regexp=^/^\+?[0-9-()]{7}+[0-9]{2}$/^`
         &validationErrorMessage=`<p class="error text-danger">Ошибки в форме. Пожалуйста, праверьте заполнение полей.</p>`
         &successMessage=`<p class="text-success">Ваше сообщение отправлено. Вам позвонят.</p>`
      ]]

      [[+fi.validation_error_message:notempty=`[[+fi.validation_error_message]]`]]
      <form action="/assets/cppv/TPL/contentC/mainPage/band1/phoneRequest/ajPhone.php" method="post" id="formPhoneRequest">
         <input type="hidden" name="fio" value="" />
          <div class="form-group">
          <label for="F1InputName">Ваше имя:<span class="error text-danger">[[+fi.error.name]]</span></label>
          <input type="text" name="name" class="form-control" id="F1InputName" placeholder="Введите Ваше Имя" value="[[+fi.name]]">
        </div>
          <div class="form-group">
          <label for="F1InputPhone">Ваш номер телефона:<span class="error text-danger">[[+fi.error.phone]]</span></label>
          <input type="text" name="phone" class="form-control" id="F1InputPhone" placeholder="Введите Ваш номер телефона" value="[[+fi.phone]]">
        </div>
          <div class="form-group">
          <label for="F1InputEmail">Email:<span class="error text-danger">[[+fi.error.email]]</span></label>
          <input type="text" name="email" class="form-control" id="F1InputEmail" placeholder="Введите Ваш email" value="[[+fi.email]]">
        </div>
            <button type="submit" class="btn btn-danger pull-right">Отправить</button>
            <div class="clearfix mrgB10_">&nbsp;</div>
      </form>



    3. хук - '...../myHook.php'
      <?php

      $name= $hook->getValue('name');
      $phone= $hook->getValue('phone');
      $email = $hook->getValue('email');

      $out= '<h3>Спасибо что обратились к нам!</h3>';
      $out.= '<h4>Ваша заявка принята.</h4>';
      $out.= '<div class="text-info">Мы вам перезвоним в ближайшее время.</div>';

      echo $out;

      /* Сюда впишите свою эл. почту */
       $address = "vinni@mail.ru, pyatachek@mail.ru, tigra@mail.ru";

      /* А здесь прописывается текст сообщения, \n - перенос строки */
       $mes = "Subject: Заказ звонка!\nPhon: $phone\nName: $name\nE-Mail: $email";

      /* А эта функция как раз занимается отправкой письма на указанный вами email */
      $sub='Заказ звонка - vseZaVashiDengi.ru'; //сабж
       $send = mail ($address,$sub,$mes,"Content-type:text/plain; charset = utf-8");
      exit();
  4. JS скрипт. Можно прямо на странице с модалью или в другом месте. Загружает форму с сервера при открытии модали. Отправляет форму, принимает ответы сервера и загружает в модаль.
    <script type="text/javascript">
       $(document).ready(function(){
            $('#ModalRequestCall').on('show.bs.modal', function (e) {
              $("#ModalRequestCall .modal-body").load("/assets/.../ajFormIt.php",
                  function (data, textStatus, XMLHttpRequest) {
                    initOnSubmit();    
                  }
              
              );                  
            });
       });

       function initOnSubmit() {
        
           $(document).on("submit","#formPhoneRequest",function(e){
                e.preventDefault();
                var m_method=$(this).attr('method');
                var m_action=$(this).attr('action');
                var m_data=$(this).serialize();
               
                $.ajax({
                    type: m_method,
                    url: m_action,
                    data: m_data,
                    resetForm: 'true',
                    success: function(result){
                        $("#ModalRequestCall .modal-body").html(result);
                    }
                });
           });
            
        }        
       
       
    </script>

При статическом подключении FormIt возникает куча проблем.

  • Перезагрузка страницы при отправке формы
  • Fierfox(например) запоминает POST переменные и при обновлении страницы снова отсылает форму с прежними данными.
  • Для борьбы с предыдущим пунктом необходимо успешный ответ перенаправлять на другую страницу
  • Организовать перенаправление на исходную страницу, иначе при простом возврате опять будет проблема с повторной отсылкой формы.
  • Да и выглядит все уж больно убого

Все эти проблемы снимаются при примешивании AJAX. Вот как я это делаю:

  1. На исходной странице размещаем контейнер для формы и JS-скрипт для AJAX-поведения

    <div class="iWant" id="iWant"> 

    </div>

    <script type="text/javascript">
       $(document).ready(function(){
              $("#iWant").load("/assets/.../aj.php",
                  function (data, textStatus, XMLHttpRequest) {
                    iWantInitOnSubmit();   
                  }         
              );
       });

       function iWantInitOnSubmit() {
       
           $(document).on("submit","#formIWant",function(e){
                e.preventDefault();
                var m_method="POST";
                var m_action="/assets/.../aj.php";
                var m_data=$(this).serialize();
                //var fill_="<h3>Ваш заказ отправлен. Ожидание ответа сервера ... </h3>";
                //$("#myModal_form").html(fill_);
                //$("#bs-oneClick-modal").find(".well").remove();
               
                $.ajax({
                    type: m_method,
                    url: m_action,
                    data: m_data,
                    resetForm: 'true',
                    success: function(result){
                        //console.log('result='+result);
                        //var data = $(result).find("#formPhoneRequest").html();
                        //console.log('data='+data);
                        $("#iWant").html(result);
                    }
                });
           });
           
        }       
      
      
    </script>

    Смысл - при загрузке страницы - делается ajax-загрузка формы в контейнер. И при каждой сабмите - тот-же самый ajax-запрос. А там парсится чанк с FormIt и формой. Результат ajax-запроса опять помещается в контейнер.
  2. В каталог кладем файл '/assets/..../aj.php'
    <?php

    require_once $_SERVER['DOCUMENT_ROOT'].'/manager/config.core.php';
    require_once MODX_CORE_PATH.'model/modx/modx.class.php';
    $modx = new modX();
    $modx->initialize('web');

    $out="";

    $Tpl=file_get_contents($_SERVER['DOCUMENT_ROOT']."/assets/.../FormItTpl.tpl");
    $uniqid = uniqid();
    $chunk = $modx->newObject('modChunk', array('name' => "tmpCnank-{$uniqid}"));
    $chunk->setCacheable(false);

    $params=array();
    $params['fi']=array();
    $params['fi']['error']=array();
    $params['fi']['error']['name']='';
    $params['fi']['error']['email']='';
    $params['fi']['error']['phone']='';
    $params['fi']['validation_error_message']='';
    $params['fi']['name']='';
    $params['fi']['email']='';
    $params['fi']['phone']='';
    $params['fi']['successMessage']='';

    $out.=$chunk->process($params,$Tpl);

    echo $out;
  3. Туда же - 'assets/.../FormItTpl.tpl'
    
    [[FormIt?
       &hooks=`myHook.php`
       &validate=`fio:blank,
          name:required:stripTags,
          email:email,
          phone:regexp=^/^\+?[0-9-()]{7}+[0-9]{2}$/^`
       &validationErrorMessage=`<p class="error text-danger">Ошибки в форме.</p>`
       &successMessage=`<p style="color:#000000;">Спасибо! Ваше сообщение получено. Мы обязательно с вами свяжемся!</p>`
    ]]

          <div class="I2_1"><div style="font-size:21px;"><span class="redCppv">У</span>величить продажи?</div>
             <div style="font-size:27px; top:-10px;">Мы знаем <span class="redCppv">КАК!</span></div>
          </div>
          <div class="I2_2">
          мы сделаем все для вас за ваши деньги
          </div>  
          <div class="I2_3">
               <form action="[[~[[*id]]]]#iWant" method="POST" id="formIWant">          
                  <input type="text" name="name" placeholder="Ваше имя" value="[[+fi.name]]" />    
                  <input type="text" name="phone" placeholder="Ваш телефон" value="[[+fi.phone]]" />    
                  <input type="text" name="email" placeholder="Ваш e-mail" value="[[+fi.email]]" />
                  <div class="btnPic">
                     <input type="submit" name="call" value="ХОЧУ заказать!"/>
                  </div> 
                  <div class="I2_3_5 ff f10 lh1">
                          *Отправляя заявку, я соглашаюсь на обработку своих персональных данных, указанных в заявке, с целью информирования
                          меня об услугах организации.
                  </div>      
               </form>     
               [[+fi.validation_error_message:notempty=`<div class="alert alert-warning fade in posR">
               <button type="button" class="close" data-dismiss="alert" aria-hidden="true">X</button>
               <strong>
               [[+fi.validation_error_message]]
               </strong>
               <div class="text-danger">Имя:[[+fi.error.name]]</div>          
               <div class="text-danger">Телефон:[[+fi.error.phone]]</div>          
              
                </div> 
                     
               `]]
              
               [[+fi.successMessage:notempty=`<div class="alert alert-info fade in posR">
               <button type="button" class="close" data-dismiss="alert" aria-hidden="true">X</button>
               <strong>
               [[+fi.successMessage]]
               </strong>
              
                </div>  `]]
          </div>
         
  4. И наконец хук:
    <?php

    $name= $hook->getValue('name');
    $phone= $hook->getValue('phone');
    $email = $hook->getValue('email');

    /* Сюда впишите свою эл. почту */
     $address = "vinni@mail.ru, tigra@mail.ru, prostoKozel@mail.ru";

    /* А здесь прописывается текст сообщения, \n - перенос строки */
     $mes = "Subject: Заказ 'Хочу увеличить!'!\nТелефон: $phone\nName: $name\nE-Mail: $email";

    /* А эта функция как раз занимается отправкой письма на указанный вами email */
    $sub='Заказ " - СделаемВсе.рф'; //сабж
    /*$email='Заказ'; // от кого*/
     $send = mail ($address,$sub,$mes,"Content-type:text/plain; charset = utf-8");
    return true;

В итоге имеем форму внешне как статическую. Но все работает через ajax. С выводом ошибок заполнения и сообщения об успешной отправке в алерте Bootstrap. Поскольку нет пересчета страницы с формой - то и нет связанных с этим артефактов. Еще одним плюсом является расположение всех связанных файлов в одном каталоге. Что очень удобно при сопровождении.

FormIt - весьма навороченная штука. И позволяет работать и в классическом варианте, и через AJAX.


Комментарии 0






Разрешённые теги: <b><i><br>Добавить новый комментарий: