Унификация представления (View) для быстрого отображения любых данных веб-приложения (на примере Codeigniter)

view-unufication
view-unufication

Концепция

Обычная структура проекта, написанного с использованием MVC подхода подразумевает наличие (как правило) трех файлов для каждого модуля:

  • модели (работа с базой данных);
  • контроллера (обработка полученной информации, логика приложения);
  • вида, в котором происходит отображение данных, пришедших из модели через логику контроллера.

Если у вас во многих модулях приложения идет обработка типичных данных со схожей структурой (например, выборка и показ информации в табличной форме), появляется масса файлов Вида, код которых лишь незначительно отличается друг от друга. В то же время для каждого модуля приходится рутинно указывать имена полей, отображаемых на странице, формах просмотра и редактирования записей.

К счастью основной код Вида можно организовать так, чтобы его не нужно было вообще менять. В результате основную часть — html-верстку — удобней разместить сразу после шаблона хедера страницы. Теперь она доступна для любой части приложения. Но отображать будет те данные и таким образом, как нам необходимо.

Реализация

Вносим коррективы в контроллер

Чтобы вид «знал» что и как ему отображать, он должен получить эту информацию (помимо обработанных данных) от контроллера. Для наглядности поставим себе три задачи, решение которых необходимо в 99% случаях разработки веб-приложения, а именно, формирование «на лету»:

  1. Кнопок действий с текущей записью (просмотр, редактирование, удаление).
  2. Заголовков таблиц и форм, а также их данных.
  3. Url для ajax запросов к БД, посредством которых будет делаться выборка данных или их изменение.

Пример файла котроллера, учитывающего эти три момента:

// ========== заголовок страницы ==================
           
            $this->data\\['page_title'] = 'Акти оприходования продукции'; 
         
           /*=================================================
           * СИНТАКСИС передачи form_el (первые 7 символов - служебные):
           *==================================================
           * Первые три символа КЛЮЧА массива (до |) - обозначение типа 
           * элемента управления на форме:
           * inp - input
           * sel - select
           * chk - checkbox
           * rad - radio 
           * -------------------------------------------------
           * второе значение 1 символ: h - hidden, v - visibility - видимость поля.
           * второе значение 2 символ: d - disable, e - enable редактирование поля.
           * ==================================================*/
          
            $this->data ['tbl_str']=array('id'=>'id',
                                        'Дата'=>'date_doc',
                                        'Партия'=>'num_batch',
                                        'Продукция'=>'nb',
                                        'Общий вес'=>'quantity',                                    
                                        'Ед. изм'=>'full_name',   
                                        'Потребитель'=>'consum_name', 
                                        'Статус документа'=>'doc_state'
                                        );
           
           $this->data ['form_el']=array('inp|vd|id'=>'id',
                                        'inp|vd|Дата'=>'date_doc',
                                        'inp|ve|Партия'=>'num_batch',
                                        'inp|ve|Продукция'=>'nb',
                                        'inp|ve|Общий вес'=>'quantity',
                                        'sel|ve|Ед. изм.'=>'id_unit',                                      
                                        'sel|ve|Потребитель'=>'id_consumer',
                                        'sel|ve|Статус док.'=>'id_doc_state'
                                        );
  
            // ====== куда отсылать аякс-запрос из скрипта ========
           
            $this->data ['ajax_url']=site_url('products/Ctrl_akt_prod_incoming'); 
            
            // ===== какие кнопки отображать на форме ===========
            
            $this->data ['isAddButton']=1;
            $this->data ['isBrowseButton']=1;
            $this->data ['isEditButton']=1;
            $this->data ['isDeleteButton']=1;
            
            // = вывод шаблона и передача установленных переменных ==
            
            $this->render_template('products/v_akt_prod_incoming', $this->data);

Итак, по кнопкам (отображать или нет) передаем 1/0.

Названия столбцов таблицы и элементов форм, сопоставленные с соответствующими полями БД заносятся в два ассоциативных массива. При этом ключи массива form_el в первых 7 символах содержат кодировку типа элемента формы (текстовое поле или выпадающий список), а также их атрибуты (hidden/visibility, enabled/disabled).

Наконец, в переменную data[‘ajax_url’] заносим ссылку на контроллер, который будет обрабатывать аякс-запросы. Конкретную функцию (save, update…) добавим потом в конце строки параметра url ajax запроса.

По контроллеру все. Идем дальше.

Унифицируем html-верстку вида

Чтобы это сделать, обработаем в цикле массив с именами полей для отображения на странице и на формах.

Часть верстки вида, отвечающая за вывод формы редактирования:

<!-- ---------------------------- MODAL EDIT -->
<form id="my_edit_modal">
    <div class="modal fade" id="Modal_Edit" tabindex="-1" role="dialog" 
         aria-labelledby="exampleModalLabel" aria-hidden="true">
        <div class="modal-dialog modal-lg" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="exampleModalLabel">Редактирование: 
                        <?php echo $page_title; ?> </h5>
                    <button type="button" class="close" data-dismiss="modal" 
                            aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">

                    <?php
                    //поля выборки - они же - подписи полей формы. 
                    //Передается из контроллера.
                    foreach ($form_el as $key => $value) {

                        $type_input = substr($key, 0, 3);
                        $input_par = substr($key, 4, 2);

                        switch ($type_input) {
                            case "inp":
                                if ($input_par == "hd") {
                                    echo "<div class='form-group row'>";
                                    // echo "<label class='col-md-2 col-form-label'>".substr($key,7)."</label>";
                                    echo "<div class='col-md-10'>";
                                    echo "<input type='text' name='" . $value . "_edit' "
                                    . "id='" . $value . "_edit' class='form-control' "
                                    . "placeholder='" . $value . "' readonly hidden>";
                                } else {
                                    if ($input_par == "vd") {
                                        echo "<div class='form-group row'>";
                                        echo "<label class='col-md-2 col-form-label'>"
                                        . "" . substr($key, 7) . "</label>";
                                        echo "<div class='col-md-10'>";
                                        echo "<input type='text' name='" . $value . "_edit' "
                                        . "id='" . $value . "_edit' class='form-control' "
                                        . "placeholder='" . $value . "' disabled readonly>";
                                    } else {
                                        echo "<div class='form-group row'>";
                                        echo "<label class='col-md-2 col-form-label'>"
                                        . "" . substr($key, 7) . "</label>";
                                        echo "<div class='col-md-10'>";
                                        echo "<input type='text' name='" . $value . "_edit' "
                                        . "id='" . $value . "_edit' class='form-control' "
                                        . "placeholder='" . $value . "'>";
                                    }
                                }
                                break;

                            case "sel":

                                if ($input_par == "hd") {

                                } else {
                                    if ($input_par == "vd") {
                                        echo "<div class='form-group row'>";
                                        echo "<label class='col-md-2 col-form-label'>"
                                        . "" . substr($key, 7) . "</label>";
                                        echo "<div class='col-md-10'>";
                                        echo "<select name = '" . $value . "_edit' id='" . $value . "_edit' "
                                        . "class='form-control' disabled readonly>";
                                        echo "<option value='' disabled "
                                        . "selected>Оберіть значення</option>";
                                        echo "</select>";
                                    } else {
                                        echo "<div class='form-group row'>";
                                        echo "<label class='col-md-2 col-form-label'>"
                                        . "" . substr($key, 7) . "</label>";
                                        echo "<div class='col-md-10'>";
                                        echo "<select name = '" . $value . "_edit' "
                                        . "id='" . $value . "_edit' class='form-control'>";

                                        echo "<option value='' disabled selected>....</option>";
                                        echo "</select>";
                                    }
                                }

                                break;

                            case "chk";

                                break;

                            default:
                                break;
                        }
                        echo "</div>";
                        echo "</div>";
                    }
                    ?>

                </div>
                <div class="modal-footer">
                    <button class="btn btn-secondary" 
                            data-dismiss="modal">Отменить</button>
                    <button type="submit" id="btn_update" 
                            class="btn btn-primary">Сохранить изменения</button>
                </div>
            </div>
        </div>
    </div>
</form>
<!-- ------------------------------ END MODAL EDIT-->

Пару слов об этом коде. У меня все формы сверстаны в одном файле виде модальных окон, которые открываются по необходимости. Таким образом, нужно сделать так, чтобы имена и id элекментов не повторялись в пределах страницы. Это достигается путем добавления к стандартному имени или id соответствующей приставки:

  • Просмотр — _browse;
  • Редактирование — _edit;
  • Добавление — _add.

В результате для поля id формы просмотра записи получаем код:

<input type="text" name="id_browse" id="id_browse" class="form-control" placeholder="id" disabled="" readonly="">

Для формы редактирования:

<input type="text" name="id_edit" id="id_edit" class="form-control" placeholder="id" disabled="" readonly="">

Все это было сформировано конструкцией типа:

echo "<input type='text' name='" . $value . "_edit' "
                                    . "id='" . $value . "_edit' class='form-control' "
                                    . "placeholder='" . $value . "' readonly hidden>";

Адаптируем скрипты

Приведу пример скрипта, отвечающего за вывод формы редактирования записи:

$('#show_data').on('click','.item_edit',function open_modal_edit(){    
            $('#Modal_Edit').modal('show');
              var form_el = <?php  echo json_encode($form_el); ?>;// передаем объект JSON
              // из контроллера - список полей выборки.
                for (key in form_el) { // перебор объекта и заполнение полей формы
                     if ($('[name='+form_el[key]+'_edit').is('input:text')){      
                     }
                     else{  // чистим селекты от старых записей             
                         $('#'+form_el[key]+'_edit').find('option').remove();
                         // утснавливаем option для отображения по умолчанию.
                         $('#'+form_el[key]+'_edit').append("\
             <option value='' disabled selected></option>");
                     }       
                }
//Получаем id выбраной в таблице записи из кнопки Edit (которая нажата, 
//потому сейчас - this)
var id = $(this).data('id');
                   
// --------------------------------------------------------
// аякс запрос для заполнения селекта  справочника единиц измерений
// --------------------------------------------------------
                $.ajax({
                    type : "POST",
                    url  : '../spr/Ctrl_spr_units/get_spr_for_UI',
                    dataType : "json",
                    success: function(data){
                        for(i=0; i<data.length; i++)  {
                               $("#id_unit_edit").append("\
                <option value='"+data[i].id+"'>"+data[i].full_name+"</option>"); 
                          } 

var ajaxurl= '<?php echo ($ajax_url)?>';                

 $.ajax({
                    type  : "POST",
                    url   : ajaxurl+'/data_by_id',
                    dataType : 'json',
                    data: {id:id},
                    success : function(data){
                        
                        for(i=0; i<data.length; i++)  {   
                  // для каждого элемента массива data[] (объекты-записи из БД):
                                $.each(data[i], function (key, value){
                                   if ($('[name='+key+'_edit]').is('input:text')){
                                          $('[name='+key+'_edit]').val(value);      
                                   }
                                   if( $('#'+key+'_edit').prop('type') == 
                                           'select-one' ) {  
                                    $('#'+key+'_edit option[value="'+value+'"]')
                                            .prop('selected', true);
                                       }
                                });
                        }
                            } // -------------- End of Success get data by id ---------------------
                    }); // End of Ajax get data by id

Обратите внимание на конструкцию:

var form_el = <?php  echo json_encode($form_el); ?>;

Здесь мы в переменную скрипта получили из контроллера в json-представлении массив с именами полей форм. Далее в цикле for…key обрабатываем селекты формы, очищая их от данных. Наконец получаем данные по текущей записи из базы, отправляя запрос на функцию data_by_id контроллера, имя которого перед этим получено через переменную ajaxurl:

url : ajaxurl+'/data_by_id',

Вывод

Таким способом легко переписать любой модуль приложения. Меняется код модели и контроллера. Что касается отображения — скрипты и html-верстка остаются одинаковыми. Работы с полями форм осуществляется через переменные, через них же получается url для ajax запроса на вывод.

Чтобы использовать такой способ важно хорошо продумать структуру базы данных, чтобы однотипные данные размещались в таблицах с одинаковыми именами полей (в случае справочников). Там, где по каким-то причинам это невозможно, имена полей для отображения данных переопределяются в sql запросе, после чего передаются из контроллера в вид.

Если есть вопросы по поводу применения описанного способа, обращайтесь в комментарии.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.