Генерация расписания занятий на pdoTools

Увидел недавно вопрос на сообществе — человек хочет сгенерировать таблицу с расписанием занятий по дням.
Казалось бы, задача несложная, но это совсем не так. Стандартные сниппеты не предназначены для такой работы и их приходится запускать на каждый день недели. И даже если вас не волнует скорость работы, то в итоговой таблице будут пропущенные ячейки, что совсем не айс.
Можно сделать свой компонент расписаний, но это нужно далеко не всем, тем более, для вывода всего одной недели из дерева.
Поэтому предлагаю вам готовое решение, а заодно и демонстрацию работы с pdoTools. Конечно, можно было бы обойтись и родными методами MODX, но с ним быстрее.
Все нужные данные выбираются за один запрос, а дальше очень быстрая обработка и оформление на PHP.
Вызов на странице:
<table border="1" cellpadding="5">
<thead>
<tr>
<th>Понедельник</th>
<th>Вторник</th>
<th>Среда</th>
<th>Четверг</th>
<th>Пятница</th>
<th>Суббота</th>
<th>Воскресенье</th>
</tr>
</thead>
<tbody>
[[!pdoSchedule?
&start=`2`
&tpl=`@INLINE <td><a href="/[[+uri]]">[[+pagetitle]]</a></td>`
&tplEmpty=`@INLINE <td> </td>`
&tplRow=`@INLINE <tr>[[+days]]</tr>`
]]
</tbody>
</table>Сниппет pdoSchedule:
<?php
// Подключаем pdoFetch, потому что нам нужно работать с БД
$pdo = $modx->getService('pdoFetch');
// Задаем условия выборки: опубликованные ресурсы, потомки указанного родителя
$parents = $modx->getChildIds($start, 1);
$where = array(
'published' => 1,
'deleted' => 0,
'parent:IN' => $parents
);
// Дополнительные параметры для выборки
$options = array(
// Присоединяем родителей ресурсов (дни недели)
'innerJoin' => array(
'Parent' => array(
'class' => 'modResource',
'alias' => 'Parent',
'on' => 'Parent.id = modResource.parent'
)
)
,'select' => array(
'modResource' => 'all',
// И выбираем их индекс
'Parent' => 'Parent.menuindex as dow'
)
// Указываем сортировку результатов по индексу документа внутри дня
,'sortby' => 'menuindex,dow'
,'sortdir' => 'asc'
,'includeTVs' => !empty($includeTVs) ? $includeTVs : ''
);
// Выбираем ресурсы, подходящие под условия
$collection = $pdo->getCollection('modResource', $where, $options);
// Оформляем их как массив дней недели, используя индекс дней (поле dow)
$week = array();
foreach ($collection as $v) {
if (!isset($week[$v['dow']])) {
$week[$v['dow']] = array();
}
$week[$v['dow']][] = $v;
}
// Осталось только оформить дни в строки таблицы
$output = $days = '';
// Бесконечный цикл
while (true) {
$in = 0;
// Для перебора под дням недели
for ($i = 0; $i <= 6; $i++) {
// Если день еще не пуст
if (!empty($week[$i])) {
// Забираем первый элемент массива в нём
$days .= $pdo->getChunk($tpl, array_shift($week[$i]));
// И плюсуем индиктор того, что строка не пустая
$in++;
}
// Иначе вставляем пустую ячейку
else {
$days .= $pdo->getChunk($tplEmpty);
}
}
// Если у нас строка с днями - добавляем ее в результаты
if ($in) {
$output .= $pdo->getChunk($tplRow, array('days' => $days));
// И обнуляем дни для следующей строки
$days = '';
}
// А если документы закончились - пора выходить из цикла
else {
break;
}
}
// Возвращаем оформленные ряды таблицы
return $output;Результат:

Дни недели можно спокойно переименовывать, а документы внутри менять местами. Все привязано к индексу, а не названиям.
Думаю, комментариев в коде вполне достаточно. Если есть вопросы — задавайте.
Комментарии: 28
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
1. Это ответ на конкретно поставленный вопрос. Человек спросил про вывод ресурсов в виде календаря.
2. Мне не нравится MIGX. На мой взгляд — это один большой костыль для тех, кому лень писать свои компоненты и работать напрямую с таблицами.
Когда у меня возникла такая задача на atletik-city.ru — я решил это написанием удобного компонента и он до сих пор работает. Там, конечно, побольше функций.
Свой компонент намного лучше. И MIGX не во всех случаях подходит для решения подобных задач.
Вообще по моему мнению модыксу не хватает одного важного дополнения — мастера быстрого написания компонентов, без глубоких знаний программирования, для решения несложных задач подобного типа. Рано или поздно такой мастер думаю будет написан.
MIGX — попытка сделать что-то похожее в рамках работы с конкретного ресурса. Но у него есть множество минусов, к примеру данные вносимые в MIGX не будут участвовать в поиске, или будут видны в виде json. Да и сложен он для неопытного пользователя.
Или ты знаешь термех, сопромат и строишь серьезные здания, или у тебя кубики лего и ты играешь в песочнице.
MIGX очень многое позволяет, потому и популярен. Я не принижаю его возможности, но лично мне он не нравится. Пару раз пытался использовать — в итоге перематерился и написал свое.
В общем: больше решений, хороших и разных!
Я себе представляю это примерно так:
1) описание и создание таблицы в бд
2) выбор для каждого поля в бд типа ввода в форме (по типу тех же tv)
3) выбор метода вывода в менеджере, отдельным компонентом или новым типом ресурса
4) создание схемы и классов добавления, редактирования, удаления
5) запаковывание это все в пакет и установка
А выводить это все во фронтэнде можно твоим pdoTools.
Я бы такой компонент купил бы минимум на несколько сайтов. :)
Берешь заготовку, пишешь модель, добавляешь сниппеты, страницу в админке и упаковываешь.
Я так все свои компоненты и делаю, обновляя этот modExtra, когда нужно.
Все дальнейшие упрощения — суть ограничения. Это когда тебе вместо песка и цемента дают готовые ж\б конструкции. Хочешь сарай, гараж, или будку для собаки — херачь это блоками 2х1.5 из бетона.
Я все-таки за песок+цемент и вдумчивое перемешивание с водой.
Создавал новый тип страниц или через плагин при открытие документа привязываешь свой компонент, расскажи если не трудно.
Нужен точно такой же функционал. Можно ли купить этот компонент?
Код не универсален, документации нет, поддержки тоже.
Делаю так:
И в сниппете раскоментировал и подправил синтаксис в этой строке: // Можно указать и выборку ТВ параметров, если нужно:
,'includeTVs' => 'trener'
поля все заполнены, но все равно не выводит tv :(
В сниппете TV вызываю так (как в pdoResources):
В чанке row_group2 вывожу так:
В сниппете так:
И все равно не выводит текст сниппета. Что не так делаю?
Я не вижу, а значит выводить нужно
Или указать в сниппете еще и tvPrefix:
Сам MODX видит miniShop2:
Василий не подскажешь, как заставить pdoFetch видеть минишоп?