Выборка ресурсов с TV-параметрами.

Здравствуйте.

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



Вот что пока получается:

<?php
$parent = 7;
$resources = array();

$q = $modx->newQuery('modResource');
$q->leftJoin('modTemplateVarResource', 'modTemplateVarResource', 'modResource.id = modTemplateVarResource.contentid');

$q->where(array('modResource.parent' => $parent, 'modResource.published' => 1, 'modResource.deleted' => 0));

$q->select(array('modResource.*', 'modTemplateVarResource.*'));
if ($q->prepare() && $q->stmt->execute()) {
	$resources = $q->stmt->fetchAll(PDO::FETCH_ASSOC);
}

echo '<pre>';
echo print_r($resources);
echo '</pre>';

Понимаю, что это не совсем правильно, но не представляю как корректно нужно присоединить таблицу с TV.
alex1988
25 февраля 2015, 00:22
modx.pro
1
3 604
0

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

alex1988
27 февраля 2015, 23:28
0
Судя по количеству просмотров за 3 дня и отсутствию ответов, те кто прочитал пост либо не знали как помочь с проблемой, либо с мыслями вроде «еще один новичок с глупыми вопросами, который не может даже разобраться в документации» пролистывали дальше. И не удивительно — вопрос на самом деле кажется пустяковым, но вызвал у меня затруднение. И вот почему.

Задача такая: есть ресурсы с шаблоном «Семинар» и прикрепленными к ним несколькими TV. В частности TV с именем seminarDatestart, которая содержит дату начала семинара. Нужно выбрать все семинары, у которых дата начала старше текущей даты, т.е. семинары, которые еще не начались.

Все выглядит просто. Используем pdoResources для выборки:

[[pdoResources?
	&parents=`7`
	&tpl=`tpl.seminar`
	&sortby=`seminarDatestart`
	&sortdir=`ASC`
	&depth=`3`
	&limit=`0`
	&hideContainers=`1`
	&includeTVs=`seminarDatestart,seminarDateend,seminarCity`
	&where=`{"seminarDatestart":"[[NowTime]]"}` // Сниппет NowTime возвращает текущее время в timestamp
]]

Все выглядит корректно, но сниппет ничего не возвращает. Убираем строку &where=`{«seminarDatestart»:"[[NowTime]]"}` — возвращает все семинары, как и ожидается. Значит условие where не работает.

После долгих проб различных вариантов, решил заглянуть в базу данных. Оказалось, что значение seminarDatestart хранится в базе строкой вида 2015-02-20 23:31:00.

Что за бред?! Зачем вообще хранить в базе дату в виде отличном от timestamp — строку ни отсортировать, ни отфильтровать нормально не получится?! Если я в этом не прав, приведите примеры почему.

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

Использовать getCollection изначально не хотелось, потому что функция возвращает коллекцию xPDOObjects, что, на мой взгляд дольше выполняется, чем получение чистого массива данных. Вот тут я могу оказаться не прав и с удовольствием выслушаю замечания.

Но даже и с getCollection решить проблему не получалось — не нашел ни одного примера выборки ресурсов со всеми TV-параметрами. Встречались примеры вроде этого, в котором выбираются ресурсы с одним определенным TV. Но на их основе ничего подходящего реализовать у меня не получилось.

Задачу решить не смог, решил передохнуть и подождать помощи в топике. А через три дня сел со свежей головой и сходу придумал альтернативный вариант решения, который в принципе меня удовлетворяет по простоте и скорости.

<?php
$parent = 7;
$tmplvarid = 3; // id TV параметра seminarDatestart
$output = '';
$resourcesIds = array();

$nowTime = time();

$q = $modx->newQuery('modTemplateVarResource');
$q->where(array('modTemplateVarResource.tmplvarid' => $tmplvarid));
$q->select(array('modTemplateVarResource.*'));

if ($q->prepare() && $q->stmt->execute()) {
	while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
		if (strtotime($row['value']) > $nowTime) {
			$resourcesIds[] = $row['contentid'];
		}
	}
}

if (!empty($resourcesIds)) {
	$output = $modx->runSnippet('pdoResources',
		array(
			'parents' => $parent
			,'resources' => implode(',', $resourcesIds)
			,'limit' => 0
			,'tpl' => 'tpl.seminar'
			,'sortby' => 'seminarDatestart'
			,'sortdir' => 'ASC'
			,'depth' => 3
			,'hideContainers' => 1
			,'includeTVs' => 'seminarDatestart,seminarDateend,seminarCity'
		)
	);
}

echo $output;

Выбираем все TV с id = 3 — это идентификатор seminarDatestart. Возвращается примерно следующий массив:

Array
(
    [0] => Array
        (
            [id] => 5
            [tmplvarid] => 3
            [contentid] => 45
            [value] => 2015-02-20 23:31:00
        )

    [1] => Array
        (
            [id] => 12
            [tmplvarid] => 3
            [contentid] => 46
            [value] => 2015-03-11 09:12:00
        )

)

Далее в цикле смотрим: если значение TV больше текущего времени, то сохраняем id ресурса с этим TV, иначе — пропускаем. В результате мы получаем массив с идентификаторами нужных нам ресурсов. А дальше мы можем вызвать тот же pdoResources указав эти индентификаторы в параметре resources.

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

Ну и, кроме всего прочего, вопрос топика то остается открытым — как, все таки, через newQuery получить список ресурсов со всеми TV-параметрами? Желательно без getCollections.
    Василий Наумкин
    28 февраля 2015, 07:48
    0
    Оказалось, что значение seminarDatestart хранится в базе строкой вида 2015-02-20 23:31:00.

    Что за бред?! Зачем вообще хранить в базе дату в виде отличном от timestamp — строку ни отсортировать, ни отфильтровать нормально не получится?! Если я в этом не прав, приведите примеры почему.
    Это формат называется, как ни странно, datetime.

    Он отлично сортируется и в начальном варианте твой сниппет NowTime должен был просто делать так:
    <?php
    return date('Y-m-d H:i:s', time());

    Ну а в pdoResources его нужно вызывать вот так:
    [[!pdoResources?
    	&parents=`7`
    	&tpl=`tpl.seminar`
    	&sortby=`seminarDatestart`
    	&sortdir=`ASC`
    	&depth=`3`
    	&limit=`0`
    	&hideContainers=`1`
    	&includeTVs=`seminarDatestart,seminarDateend,seminarCity`
    	&where=`{"seminarDatestart:>":"[[NowTime]]"}`
    ]]
    Обрати внимание, что в условии seminarDatestart:>, то есть дата больше, а сам pdoResources должен быть некэшрованным, потому что текущее время непостоянно.

    Вот и всё, вопрос решен.

    Свой велосипед, понятно, всегда приятнее и лучше, но уж что даты сортируются — нужно знать. В последней версии pdoTools даже появился параметр &sortbyTVType с вариантами decimal, integer, string и datetime.
      alex1988
      02 марта 2015, 07:26
      0
      Спасибо за дельные замечания. В результате остановился на таком варианте:

      [[!pdoResources?
      	&parents=`7`
      	&tpl=`tpl.seminar`
      	&sortby=`seminarDatestart`
      	&sortdir=`ASC`
      	&depth=`3`
      	&limit=`0`
      	&hideContainers=`1`
      	&includeTVs=`seminarDatestart,seminarDateend,seminarCity`
      	&where=`{"seminarDatestart:>":"[[NowTime:date=`%Y-%m-%d %H:%M:%S`]]"}`
      ]]
    Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
    3