Простая модель для «чайников»

Оказывается, есть на свете люди, которые не могут понять Простую модель. Я как большой поклонник этой модели данных попробую им немного помочь.

Рассмотрим простой пример. Допустим, вам нужно создать сайт, состоящий из двух страниц – главной (кто не в курсе, она имеет адрес / :)) и внутренней по адресу /page, например. В соответствии с Простой моделью создаем таблицу категорий с такими записями:

INSERT INTO `site_categories` (`id`, `name`, `content`, `bits`) VALUES
('', 'Главная страница', '', 0),
('page', 'Внутренняя страница', '', 0);

Кто еще не догадался, как сделать роутинг по этой таблице? Можно брать путь из адреса поступившего запроса и обрезать первый слеш при помощи функции ltrim. Можно обрезать первый и последний слеши пути при помощи функции trim (на случай, если путь будет таким: /page/). Посмотрите, как формируются значения $p и $px в статье про единую точку входа. Однако делать выборку из таблицы категорий по практически полному пути было бы слишком просто даже для простой модели.

В рассматриваемой модели символьный идентификатор категории НЕ должен содержать слеши! По крайней мере тогда, когда роутинг по данной категории должен завершаться успехом. Такой подход имеет определенные преимущества: не нужно выполнять запрос к базе данных по многокомпонентному пути, если ожидается поступление только однокомпонентного пути; не нужно дублировать одинаковый первый компонент при хранении многокомпонентных путей.

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

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

Путь$p0$p1
/
/pagepage
/page/1page1
/page/1/extrapage1/extra

Комбинация, когда $p0='', а $p1='непустая строка', обычно невозможна, т.к. пути с множественными (т.е. несколькими подряд идущими) слешами преобразуются в «нормализованный» вид, например путь //page преобразуется просто в /page (только за счет (l)trim можно избавиться от множественных первых слешей, что позволяет избежать появления показанной комбинации).

После выделения двух частей пути в параметры $p0 и $p1 выполняется запрос к таблице категорий по значению первого из них, т.е. происходит попытка найти категорию с id='$p0'. В общем-то на этом можно было остановиться и запускать контроллер с именем из поля module* найденной записи, но фронт-контроллер обычно не ограничивается этим и, если это позволяет тип найденной категории, выполняет запрос к соответствующей таблице объектов по значению параметра $p1, т.е. происходит попытка найти объект с id='$p1'.

* Когда поле module отсутствует или пустое, имя контроллера определяется по значению поля id найденной категории. При этом категория с id='' не должна никого смущать. За счет добавления окончания 'Controller' или расширения имени файла может формироваться вполне осязаемое имя контроллера или файла контроллера.

Получается, что значение $p0 является селектором категории, а значение $p1 – селектором объекта. Когда $p0='', можно говорить о наличии пустой категории, а когда $p0='непустая строка' – о наличии непустой категории. Аналогично когда $p1='', можно говорить о наличии пустого объекта, а когда $p1='непустая строка' – о наличии непустого объекта.

Запрос к таблице объектов выполняется НЕ всегда даже при наличии непустого объекта. И наоборот может быть выполнен даже при наличии пустого объекта. Точное условие выполнения второго запроса показано в этом комментарии. А для «чайников» я составил такую таблицу:

Тип категорииВид объектаВторой запрос
1 (012)любойНЕ выполняется
2 (102)пустойНЕ выполняется
2 (102)непустойвыполняется
3 (112)любойвыполняется

Для категории типа 0 (002) использовать непустые объекты запрещено, поэтому я не включил этот тип в таблицу. Но все-таки скажу, что фронт-контроллер не будет выполнять запрос к таблице объектов (для поиска пустого объекта). И он должен гарантировать, что объект всегда пуст, поэтому в контроллере можно не обращать внимания на значение параметра $p1.

Даже если вы создаете простой фронт-контроллер, который выполняет только один запрос, нужно запускать контроллер по условию «тип категории больше 0 ИЛИ объект пустой». Если более формально:

$mode > 0 || strlen($p1) == 0

Если в $mode могут храниться значения, отличные от 0, 1, 2 и 3, то вместо $mode нужно написать ($mode & 3). Сравнение > 0 можно опустить, при этом и скобки вокруг $mode & 3 можно не использовать:

$mode & 3 || strlen($p1) == 0

Надеюсь, прочитав данную статью, вы сможете организовать роутинг с одним запросом к базе данных в полном соответствии с Простой моделью.

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

Отправить комментарий

Ваш адрес E-mail не будет опубликован.