Деловая неделя

Как передать Данные в Представление, если в исходной таблице БД три поля, а в итоговом HTML коде два элемента P? А потом, при добавлении нового поля в таблицу, можно было бы вносить минимум изменений в код?

ЕЖЕНЕДЕЛЬНАЯ РЕКЛАМНАЯ ГАЗЕТА ДЛЯ ПРЕДПРИЯТИЙ «Деловая неделя» (Иркутск)

Асимметрия Данных и Представления (попытка исследования)

Как послушно воспроизводят веб-мастера в своих кодах кальку "class Model – class Controller – class View"! Но кто, ть, сказал, что шаблон проектирования должен непременно воплощаться в соответственно называемых видимых кусках кода? И кто сказал, что шаблон для веб-фреймворка должен быть именно mvc?

Недавно мы говорили о неуместности кальки «паттерн проектирования» (из-за существования нормальных русских соответствий типа «шаблон», «образец», «стиль», «принцип»). Фреймворк (framework: каркас) в этом плане лучше так и оставить фреймворком («каркас» всё-таки пока ещё как-то не притягивается по значению к программированию).

Что это вообще такое – фреймворк? Википедия стыдливо прячется за расплывчатое понятие «программное обсепечение» (можно было бы уж хотя бы «систему» выбрать в качестве родового слова). Если отбросить формальности, по сути, веб-фреймворк – это просто сайт (полупустой или совсем пустой, без текстов и картинок), в котором легко можно заменять некоторые части. А именно (по возрастанию сложности):

1. Менять одни тексты на другие ("Блог веб-разработчика" -> "Блок беспартийных и безработных").

2. Менять логотипы в шапке сайта и другие картинки:

belt.gif

->

met.gif

3. Менять структуру сайта (передвинуть колонку новостей слева направо).

4. Менять тип сайта (блог на интернет-магазин).

Что надо для облегчения таких изменений на сайте? Отнюдь не шаблон mvc, а шаблон проектирования «отвязанный код» (mvc, и уж тем более ООП, его нисколько не гарантируют!), то есть стиль программирования, который сводит к минимуму зависимость одних частей кода от других. Последовательное же воплощение этого шаблона («полная инкапсуляция») уводит всё развитие программирования в сторону дурной бесконечности раздувания кода (об этом мы говорили в статье design pattern «отвязный код»).

Поэтому второй принцип после «изоляции кода» при написании фреймворка должен быть принцип экономии ресурсов сервера. Эти два принципа должны взаимно уравновешивать друг друга. И никакого mvc тут близко не стояло и роли не играло. Точнее, оно должно привлекаться постольку, поскольку выполняет задачи первого принципа («разделяй и властвуй»).

В рамках такой концепции, сколь бы торжественно мы не заявляли в заголовке class View, следующий код (чаще всего используемый в качестве примера этого самого view) ни на йоту не приближает нас к написанию идеального фреймворка:

(Пример 1.)

Здесь абсолютно неважно, используется ООП, функции, или «голый» php, а важно то, что прямолинейное следование mvc заводит в тупик автоматизацию (и, как следствие, ту самую способность легко менять структуру сайта, которую мы считаем одной из главных задач хорошего фреймворка). Принцип изоляции кода требует, чтобы никто ничего ни про кого не знал, а в примере явнее явного прописано echo $topic['author'], что в данном случае является «магической константой» (неизвестно откуда свалившейся).

Вообще говоря, само по себе использование mysql_fetch_assoc уже указывает на несовершенство, определённую связанность кода. Более правильно извлекать данные из БД примерно так:

(Пример 2.)

Где $fields – список наименований полей запроса (сформированный раньше, до получения самих данных), а $values – результирующий массив. Через шаблон тоже надо пропускать (в этом случае) данные из массива $value «побайтово», максимально дискретно – то есть добавлять каждую ячейку «не глядя», так же, как и получали сам массив:

(Пример 3.)

Где $tpl['main_td'] может быть что-то вроде <td class='%s'>%s</td>. Почему так сложно? Да как раз ради лёгкой заменяемости частей кода, удобного изменения структуры сайта. Что будет в первом случае, если в таблицу надо будет добавить одну колонку (или хотя бы просто поменять наименование поля mysql)? Во втором случае – с кодом вообще ничего не надо будет делать! Он спокойно прожуёт любое количество полей таблицы, просто дорисовав ячейку с соответствующим содержимым и атрибутом classname.

На деле, конечно, всё это гораздо сложнее. Потому что при отрисовке заголовка мы никуда не денемся – побежим искать русское наименование для новой колонки таблицы; а такое наименование из самого mysql-запроса извлечь невозможно; русские наименования для заголовков таблицы должны быть описаны где-то в отдельном месте (в массиве или в ini-файле настроек). Можно максимально приблизить к идеалу эту часть (например, создать скрипт, который будет заносить в массив или в ini-файл новое поле), но 1) мы никак не сможем запускать такой скрипт автоматом по, допустим, событию «изменение структуры mysql-таблицы» (потому что такого «события» в php не существует), 2) а главное, всё равно русское наименование придётся дописывать руками.

Но это будет одна (неизбежная, но очевидная!) точка коррекции php-кода при изменении структуры БД. Можно сделать и абсолютно идеально – добавлять (менять) поля таблиц mysql не прямыми запросами, а через конструктор, являющийся частью фреймворка: создать форму, в которой пользователь (в данном случае, администратор) будет указывать характеристики поля и его русское имя; а при получении формы на сервере скрипт будет из одних значений создавать поле в таблице, а другие значения добавлять в настроечный массив описания полей.

Вредные мелочи

Нам повезло, что в примере генерации HTML попалась таблица. Так бывает редко. Гораздо хуже, когда выводить надо не однородные элементы td, а нечто более произвольное, вида:

!I!<div class="link"> <p class="gorod">=Братск=</p> <p class="descr">Выполняем набор текстов в программах Word, Excel , а также векторизация чертежей программами AutoCAD, Компас.Без предоплаты.</p> </div>!I!

(Пример 4.)

Это фрагмент каталога ссылок (или объявлений, без разницы). Пока он вполне однородный. Но, допустим, нам надо добавить туда информацию о дате и времени ссылки (объявления). Место рядом с «городом» свободно, и в этом случае разумно его заполнить, добавив время в тот же элемент p, в котором находится и город. Ясно, что простым способом нарастить количество выводимых полей не получится:

(Пример 5.)

Потому что один и тот же $tpl['obj_el'] будет выводить один и тот же элемент p (или другой, но всё равно одинаковый с остальными полями). Можно сделать более общий шаблон ():

(Пример 6.)

Но тогда нельзя будет автоматом добавлять новые «ячейки» – нужно будет каждый раз менять шаблон. Вот такие мелкие говнистости обычно и выявляют крупные проблемы. Наша проблема на этот раз – асимметрия структур Данных и Представления. Для её решения понадобится ещё один «слой» – описание логики представления (или отделённая от реализации «модель» представления). Такой слой для данных у нас, кстати, уже есть: мы либо извлекаем структуру (описание связей системы) из mysql-запроса, либо храним её в заранее заготовленном массиве (либо смешанный вариант: частично одно, частично другое).

Разрешение асимметрии Данных и Представления

Это, наверное, основная задача при реализации mvc в вебе. Простейшая аналогия здесь: у вас есть электрическая розетка с двумя дырками и вилка с тремя стержнями. Как их соединить? Нужен переходник, у которого с одной стороны два входа, а с другой – три выхода. Попытаемся (на материале выше приведённого примера) увидеть, что у такого переходника должно быть внутри. Со стороны данных схема понятна (она уже есть в виде полученного массива). Как могла бы выглядеть схема представления? Это должен быть какой-то сложный массив, содержащий абстракции вложенных друг в друга элементов.

Создадим массив (с запасом – добавим сразу элементы для ссылки):

(Пример 7.)

И... убеждаемся, что такая схема работать не будет (состыковка схемы данных и схемы представления, позволяющая добавлять данные, не меняя скрипт вывода на экран). Видимо, тут можно использовать только «полный» шаблон (Пример 6). Только в нём надо будет обеспечить обработку отсутствия нужных данных. Это возможно только внутри шаблона-функции (а не шаблона-переменной):

(Пример 8.)

Тут пока нет проверки существования индексов входящего массива. Её организовать несложно (в цикле проверить и заполнить недостающие элементы). Но такую простую проверку можно использовать только для фиксированного шаблона (а для него вовсе и не нужна функция). Если же мы принципиально допускаем серьёзные изменения структуры шаблона (то есть ссылка на сайт – для каталога ссылок, то нет ссылки – если шаблон используется в каталоге объявлений), то после отрицательного результата проверки надо удалять (не добавлять) весь структурный блок. Примерно так:

(Пример 9.)

Да. Как видим, толстыми, тупыми и уродливыми бывают не только контроллеры. Если, конечно, исповедовать принцип «Представление ничего не знает о Данных" (или »Данные не должны зависеть от Представления""). Ну... утешает то, что по такому же принципу работают браузеры. Они обязаны предполагать во входящих данных наличие сотен разных HTML-тэгов (и все их уметь обрабатывать).

Невольно начинает казаться, что для улучшения кода (и обеспечения более логичной автоматизации) следует ввести какой-то другой принцип. Например: «Схема Данных должна заботиться о предполагаемом Представлении». То есть, если Схема Данных будет посылать Представлению какие-то дополнительные метки, намёки на сущность передаваемых объектов, это бы очень помогло сделать шаблон более компактным и удобочитаемым. Вот что приблизительно надо знать Представлению о получаемых данных:

(Пример 10.)

Хотя на самом деле Inline && Block тут лишние (Представление само может определить такие детали). А вот тип в первой строке прямо-таки революционно изменяет концепцию. Остаётся придумать, как передать мелкие объединения элементов из Схемы Данных в Схему Представления. Ну, в случае со ссылкой понятно: каждому значению просто добавлять 'type' => 'a'. Для определения не известных заранее контейнеров можно, в принципе, добавлять любой абстрактный тип (вплоть до пустого). Только надо как-то отличать один контейнер от другого (то есть тип всё-таки должен быть не пустым, а значимым). Ссылка тоже в общем-то может быть не одна на текущем уровне получения данных. С учётом всего этого, массив описаний полей таблиц мог бы быть примерно таким:

(Пример 11.)

А преобразование данных к нужному виду с помощью шаблонов изменится, соответственно, так:

(Пример 12.)

В общем, на вид получается всё хуже и хуже. Но надо работать. И уже сейчас можно сказать, что php так же неисчерпаем, как javascript.

D.M., admin

Читать все комментарии (0)

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

*Автор:
E-Mail:
*Текст: