Генерация расписания занятий на 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;

Результат:

Дни недели можно спокойно переименовывать, а документы внутри менять местами. Все привязано к индексу, а не названиям.

Думаю, комментариев в коде вполне достаточно. Если есть вопросы — задавайте.
Василий Наумкин
05 октября 2013, 03:56
modx.pro
17
6 012
0

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

Дмитрий Иванов
05 октября 2013, 09:04
0
Красиво. С бесконечным циклом понравилось.
    Александр Наумов
    05 октября 2013, 10:18
    0
    Круто, с комментариями целый урок получился!
      De Ribaskin
      05 октября 2013, 11:19
      0
      Думаю для решения этой задачи было бы практичнее использовать MIGX. Один документ без всяких вложений, с возможностью наглядного редактирования и сортировкой.
        Василий Наумкин
        05 октября 2013, 12:58
        0
        Две причины:
        1. Это ответ на конкретно поставленный вопрос. Человек спросил про вывод ресурсов в виде календаря.

        2. Мне не нравится MIGX. На мой взгляд — это один большой костыль для тех, кому лень писать свои компоненты и работать напрямую с таблицами.

        Когда у меня возникла такая задача на atletik-city.ru — я решил это написанием удобного компонента и он до сих пор работает. Там, конечно, побольше функций.
          De Ribaskin
          05 октября 2013, 14:58
          0
          Василий, безусловно ты прав и по первому и по второму вопросу, я лишь высказал мнение.
          Свой компонент намного лучше. И MIGX не во всех случаях подходит для решения подобных задач.

          Вообще по моему мнению модыксу не хватает одного важного дополнения — мастера быстрого написания компонентов, без глубоких знаний программирования, для решения несложных задач подобного типа. Рано или поздно такой мастер думаю будет написан.
          MIGX — попытка сделать что-то похожее в рамках работы с конкретного ресурса. Но у него есть множество минусов, к примеру данные вносимые в MIGX не будут участвовать в поиске, или будут видны в виде json. Да и сложен он для неопытного пользователя.
            Василий Наумкин
            05 октября 2013, 16:28
            0
            Вообще по моему мнению модыксу не хватает одного важного дополнения — мастера быстрого написания компонентов, без глубоких знаний программирования
            Такого не бывает.
            Или ты знаешь термех, сопромат и строишь серьезные здания, или у тебя кубики лего и ты играешь в песочнице.

            MIGX очень многое позволяет, потому и популярен. Я не принижаю его возможности, но лично мне он не нравится. Пару раз пытался использовать — в итоге перематерился и написал свое.

            В общем: больше решений, хороших и разных!
              De Ribaskin
              05 октября 2013, 18:08
              0
              Такого не бывает.
              Или ты знаешь термех, сопромат и строишь серьезные здания, или у тебя кубики лего и ты играешь в песочнице.
              Почему же не бывает, сделать можно все :) И модыкс — по большей части и есть те кубики лего, Большинство тривиальных задач в нем можно решить стандартными дополнениями именно методом складывания кубиков. А профи твоего уровня может писать нестандартные дополнения для решения нетривиальных задач.

              Я себе представляю это примерно так:
              1) описание и создание таблицы в бд
              2) выбор для каждого поля в бд типа ввода в форме (по типу тех же tv)
              3) выбор метода вывода в менеджере, отдельным компонентом или новым типом ресурса
              4) создание схемы и классов добавления, редактирования, удаления
              5) запаковывание это все в пакет и установка

              А выводить это все во фронтэнде можно твоим pdoTools.

              Я бы такой компонент купил бы минимум на несколько сайтов. :)
                Василий Наумкин
                05 октября 2013, 20:20
                0
                Ты сейчас описал modExtra, в целом.
                Берешь заготовку, пишешь модель, добавляешь сниппеты, страницу в админке и упаковываешь.

                Я так все свои компоненты и делаю, обновляя этот modExtra, когда нужно.

                Все дальнейшие упрощения — суть ограничения. Это когда тебе вместо песка и цемента дают готовые ж\б конструкции. Хочешь сарай, гараж, или будку для собаки — херачь это блоками 2х1.5 из бетона.

                Я все-таки за песок+цемент и вдумчивое перемешивание с водой.
            Алексей Хребтов
            08 октября 2013, 14:48
            0
            Василий подскажи, как с ресурсу привязать доп вкладку со своим компонентом?
            Создавал новый тип страниц или через плагин при открытие документа привязываешь свой компонент, расскажи если не трудно.
            Игорь Терентьев
            08 апреля 2016, 07:05
            0
            Приветствую!
            Нужен точно такой же функционал. Можно ли купить этот компонент?
              Василий Наумкин
              08 апреля 2016, 07:23
              0
              Нет, он сделан под конкретного заказчика и не готов для продажи.

              Код не универсален, документации нет, поддержки тоже.
          Роман
          07 октября 2013, 14:24
          0
          Скажите пожалуйста, как передать tv параметры в сниппет?
          Делаю так:
          [[pdoSchedule?
          &start=`7`
          &tpl=`row_group2`
          &tplEmpty=`@INLINE `
          &tplRow=`@INLINE [[+days]]`
          &includeTVs=`trener`
          ]]
          И в сниппете раскоментировал и подправил синтаксис в этой строке: // Можно указать и выборку ТВ параметров, если нужно:
          ,'includeTVs' => 'trener'

          поля все заполнены, но все равно не выводит tv :(
            Василий Наумкин
            07 октября 2013, 14:45
            0
            У меня там опечатки были — поправил, теперь должно работать.
              Роман
              07 октября 2013, 15:00
              0
              Я что то не так понял все таки, делаю так:
              В сниппете TV вызываю так (как в pdoResources):
              [[pdoSchedule?
              &start=`7`
              &tpl=`row_group2`
              &tplEmpty=`@INLINE <td> </td>`
              &tplRow=`@INLINE <tr>[[+days]]</tr>`
              &includeTVs=`trener`
              ]]
              В чанке row_group2 вывожу так:
              <span class="tibLine">[[+tv.trener]]</span>
              В сниппете так:
              ,'includeTVs' => !empty($includeTVs) ? $includeTVs : 'trener'
              И все равно не выводит текст сниппета. Что не так делаю?
                Василий Наумкин
                07 октября 2013, 16:32
                0
                А tv. откуда возьмется? Ты видишь его где-то в сниппете?

                Я не вижу, а значит выводить нужно
                [[+trener]]

                Или указать в сниппете еще и tvPrefix:
                ,'includeTVs' => !empty($includeTVs) ? $includeTVs : ''
                	,'tvPrefix' => 'tv.'
                  Роман
                  07 октября 2013, 18:29
                  0
                  Спасибо большое Василий, реально нужная и полезная вещь, давно гуглил нигде нет ничего внятного по созданию расписаний удобных для MODX, даже среди платных приложений, надеюсь многим начинающим, или простым людям которые не разбираются в программировании в силу отсутствия такого мышления :) я художник :) рисую, а вот писать сложно понять и разобраться, мозг не заточен под программирование, в общем спасибо большое, реально быстрее шуршит теперь страничка с расписанием, а то было 8 вызовов хоть и pdoResources но все равно самая тормозная страница на сайте была :)) Спасибо.
          Денис Богдановский
          21 октября 2013, 13:42
          0
          Подскажите, а как сделать расписание «вертикального типа», вот как здесь никак не могу разобраться в этом вопросе.
            Денис Богдановский
            21 октября 2013, 16:24
            0
            Ничего кроме как 7-ми вызовов pdoResource (на каждый день недели) в голову не приходит :)
            Peter Zenin
            08 ноября 2013, 04:41
            0
            Пробую в простом php файле воспользоваться pdoFetch::getCollection(), но почему-то pdoFetch совсем не видит miniShop2

            define('MODX_API_MODE', true);
            require dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/index.php';
            $pdo = $modx->getService('pdoFetch');
            
            $parent = 140;
            $allChild = $modx->getChildIds($parent,6,array('context'=>'web','class_key'=>'msCategory'));
            
            $objects = $pdo->getCollection('msProduct', array('parent:IN'=>$allChild)); // Так не видит...
            
            $objects = $pdo->getCollection('modResource', array('parent:IN'=>$allChild)); // Видит только так...
            Сам MODX видит miniShop2:

            $objects = $modx->getCollection('msProduct', array('parent:IN'=>$allChild));
            Василий не подскажешь, как заставить pdoFetch видеть минишоп?
              Peter Zenin
              09 ноября 2013, 04:57
              0
              Обновился и все работает!
                Peter Zenin
                09 ноября 2013, 05:11
                0
                Только вот msProductData все равно не видит…
              Серега Дождь
              18 ноября 2013, 13:45
              0
              Я так понимаю что сортировкой по TV этот замечательный компонент не оснащен, а что если нужно выводить расписание с фильтрами например вывести Все, Групповые, Водные и тп
                Василий Наумкин
                18 ноября 2013, 13:47
                0
                Берешь, и дописываешь ручками.
                  Серега Дождь
                  18 ноября 2013, 13:49
                  0
                  ну это понятно, не понятно как куда чего =)
                    Серега Дождь
                    18 ноября 2013, 14:09
                    0
                    не могли бы вы помочь с сортировкой, или подсказать в какую сторону копать?
                Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                28