
Концепция
Обычная структура проекта, написанного с использованием MVC подхода подразумевает наличие (как правило) трех файлов для каждого модуля:
- модели (работа с базой данных);
- контроллера (обработка полученной информации, логика приложения);
- вида, в котором происходит отображение данных, пришедших из модели через логику контроллера.
Если у вас во многих модулях приложения идет обработка типичных данных со схожей структурой (например, выборка и показ информации в табличной форме), появляется масса файлов Вида, код которых лишь незначительно отличается друг от друга. В то же время для каждого модуля приходится рутинно указывать имена полей, отображаемых на странице, формах просмотра и редактирования записей.
К счастью основной код Вида можно организовать так, чтобы его не нужно было вообще менять. В результате основную часть — html-верстку — удобней разместить сразу после шаблона хедера страницы. Теперь она доступна для любой части приложения. Но отображать будет те данные и таким образом, как нам необходимо.
Реализация
Вносим коррективы в контроллер
Чтобы вид «знал» что и как ему отображать, он должен получить эту информацию (помимо обработанных данных) от контроллера. Для наглядности поставим себе три задачи, решение которых необходимо в 99% случаях разработки веб-приложения, а именно, формирование «на лету»:
- Кнопок действий с текущей записью (просмотр, редактирование, удаление).
- Заголовков таблиц и форм, а также их данных.
- 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">×</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 запросе, после чего передаются из контроллера в вид.
Если есть вопросы по поводу применения описанного способа, обращайтесь в комментарии.