Разделы

Прямой эфир

Весь эфир | RSS
Рейтинг
+5.70
голосов:
5
avatar

Быстрые решения  

EVO Несложный SqlFilter по нескольким ТВ

В общем, потребовалось сделать в документах Глоссария 2 ТВ шки заполненные Id шками и фото документов из каталога с фильтрацией документов каталога по нескольким ТВ.

В итоге с неоценимой помощью SSDTyphon
был написан снпипет SqlFilter

параметры:
* &filterTV =`filter_1_parameter, перкаль|filter_2_sostav, хлопок|DescriptionName1, белый` //имя ТВ и через запятую какому значению равно, ТВшки через |.

В итоге фильтрация будет такой:

filter_1_parameter = перкаль OR DescriptionName1 = белый

Проверял на 3 ТВ, но должно работать вроде и при большем кол-ве. Оператор задаем так:
* &mode=`OR` // можно фильтр через AND, можно через OR

* &parentId=`2`// ID родителя, задается опционально
* &limit=`50`; // ограничение по количеству выводимых документов из базы
* &Docfield=`id` // что хотим получить на выходе? Одновременно можно вызывать либо tvReturnName либо Docfield
* &tvReturnName=`image` //если на выходе хотим вернуть значения ТВшки из каталога, задаем имя этой ТВ

Вывод — список документов через запятую, например, если Docfield=`id` вывод выглядит так: 15637,15638,15639,15640, если &tvReturnName=`image`: 1.jpg, 2.jpg, 3.jpg,4.jpg

<?php
/*[[SqlFilter?&Docfield=`id`&filterTV =`filter_1_parameter,перкаль|filter_2_sostav,хлопок|DescriptionName1,белый`&mode=`OR`]]
 * &tvReturnName=`image`   //какое ТВ возвращать
 * &filterTV =`filter_1_parameter,перкаль|filter_2_sostav,хлопок|DescriptionName1,белый` //имя ТВ 
 * &mode=`OR` // можно через AND, можно через OR
 * &parentId=`2`// ID родителя, задается опционально
 * &limit=`50`; // ограничение 
 * &Docfield=`id` // опционально одновременно можно вызывать либо tvReturnName либо Docfield
 * @EVAL $pt=$modx->getDocument($docid,'pagetitle'); return $modx->evalSnippets("[[SqlFilter?&Docfield=`id`&filterTV =`filter_1_parameter,{$pt['pagetitle']}|filter_2_sostav,{$pt['pagetitle']}`&mode=`OR`]]");
*/
 

if(!isset($filterTV)) $filterTV = 'filter_1_parameter,перкаль|filter_2_sostav,хлопок'; // - имя 1 тв по которой фильтровать, значение филтра
if(!isset($mode))$mode="OR";
$limit = isset($limit) ? $limit=" LIMIT ".$limit.";" : ';';
$parentId =isset($parentId) ? $parentId: false;

$request="";
$where="";
$select_fields = "SELECT ";

$content_base =  $modx->getFullTableName('site_content');
$site_tv_vals = $modx->getFullTableName('site_tmplvar_contentvalues');    
$site_tv=$modx->getFullTableName('site_tmplvars');

$query=" FROM $content_base as sc ";
$FilterArr=explode("|", $filterTV);

$num=0;
foreach($FilterArr as $param) {
    $Filter=explode(",", $param);
    $inputTVname=$Filter[0];
    $f_val = $Filter[1];
    $query.="LEFT JOIN ($site_tv as tv{$num}, $site_tv_vals as tv{$num}val) ".
            "ON tv{$num}.id=tv{$num}val.tmplvarid and tv{$num}val.contentid=sc.id and tv{$num}.name='$inputTVname' ";

    if ($num>0){$where.=" $mode ";}

    $where.="tv{$num}val.value='{$f_val}'";
    $num++;
}


if ($parentId){
    $where="(".$where.")";
    $children = $modx->getChildIds($parentId, 10);
    $where .= ' AND sc.id IN ('.implode(',', $children) . ') '; 
} 

$where="WHERE ".$where." GROUP BY sc.id"; 


if(isset($tvReturnName)) {
    $query.="INNER JOIN ($site_tv as tvreturn, $site_tv_vals as tvreturnval) ".
        "ON tvreturn.id=tvreturnval.tmplvarid and tvreturnval.contentid=sc.id and tvreturn.name='$tvReturnName' ";
    $select_fields.="tvreturnval.value";
}
elseif (isset($Docfield)) {$select_fields.="sc.{$Docfield}";}

else return'';

$request = $modx->db->query($select_fields.$query.$where.$limit);
//$result = $modx->db->makeArray($request);
$result = array();
while($v = $modx->db->getValue($request)){
        $result[] = $v;
    }


return implode(',', $result);
?>


На вопрос, почему не сделал через Ditto или CatalogView, скажу, что так было мне удобнее и все тут.
Также, тут задавался вопрос, можно ли фильтр по нескольким ТВ сделать через SQL, вроде бы ответили.

Если будут вопросы по исправлениям и модификациям: SQL был полностью сформирован SSDTyphon, т.к. я в этом не разбираюсь, поэтому если будут вопросы лучше на форуме шопкпера спрашивать.

PHP мой, но там надо не спрашивать, а править, я пока учусь))

[evo] вытащить ID документов определенного уровня вложенности

Добрый день, возникла потребность тащить докменты с конкретного уровня вложенности. Стандартный метод getChildIds тащат с 1 по заданный уровень.

В итоге благодаря SSDTyphon, появились два снипета:

1) Тащит только id документов из базы и выдает их через ","
<?php
if(!isset($id)) $id = 2;
if(!isset($level)) $level = 1;

if ($level > 1){
    $tblsc = $modx->getFullTableName('site_content');
    $access = "AND lvl{$level}.deleted=0 AND lvl{$level}.published=1";
    $inner = '';
    for ($i = $level-1; $i > 0; --$i){
        $nextlvl = $i+1;
        $inner .= "INNER JOIN $tblsc AS lvl{$i} ON lvl{$nextlvl}.parent=lvl{$i}.id AND lvl{$i}.deleted=0 AND lvl{$i}.published=1 ";
    }
    $sql = "SELECT lvl{$level}.id FROM $tblsc AS lvl{$level} " . $inner . "WHERE lvl1.parent=$id $access;";
    $res = $modx->db->query($sql);

    $children = array();
    while($childId = $modx->db->getValue($res)){
        $children[] = $childId;
    }
}
else{
    $children = $modx->getChildIds($id, 1);
}

return implode(',', $children);
?>


2) По сути аналог $modx->getDocuments(), где в $id заданы все документы уровня, поменяв строчку $child[] = $v['id']; на любую нужную, можно легко вытащить нужные поля документов. Можно менять SQL запрос, тогда можно ограничивать выборку еще сильнее.

<?php
if(!isset($id)) $id = 2;
if(!isset($level)) $level = 5;

if($level>2) {   
    
if(!function_exists('LevelChildren')){
        function LevelChildren($docId, $levels){
          global $modx;
          $tblsc = $modx->getFullTableName('site_content');
          $access = "AND lvl{$levels}.deleted=0 AND lvl{$levels}.published=1";
          $inner = '';
          for ($i = $levels-1; $i > 1; --$i){
            $nextlvl = $i+1;
            $inner .= "INNER JOIN $tblsc AS lvl{$i} ON lvl{$nextlvl}.parent=lvl{$i}.id AND lvl{$i}.deleted=0 AND lvl{$i}.published=1 ";
          }
          $sql = "SELECT lvl{$levels}.* FROM $tblsc AS lvl{$levels} " .
             $inner .
             "WHERE lvl2.parent=$docId $access;";
          $res = $modx->db->query($sql);
          $res = $modx->db->makeArray($res);
          foreach($res as $v) {
                    $child[] = $v['id'];
                    }

        return implode(",",$child);
}

}
    $levelID = LevelChildren($id,$level);
    return $levelID;
}
else { return '';}
?>


Вызов: [[getLevelChild&? &id = `2`&level = `5`]]

id — ID родителя. level = `5` — уровень относительно родителя (учитывая, что родитель на 1 уровне, а не 0)

Оригинал тут

ПС изначально использовал для той же цели конструкцию:

$array1 = $modx->getChildIds($parent,$depth);
$array2 = $modx->getChildIds($parent,$depth-1);
$childParents = array_diff($array1, $array2);

Авторизация на сайте средствами phpBB/XenForo топик-ссылка

Примерно год назад мне потребовалось дать возможность пользователям зарегистрированным на форуме (phpBB) авторизовываться на сайте (modX). На тот момент форум уже работал и пользователи активно общались. Решения MODxBB тогда еще не было и пришлось фантазировать.

[[!REVO]] SimpleSearch 1.5.2 pl кодировка результата поиска

5 душ один и тот-же вопрос в один день, а опубликовать вопрос на форуме?
Для тех кто в танке. По строчкам.
Открываем файл simplesearch.class.php который лежит в папке
core/components/simplesearch/model/simplesearch/

( Читать дальше )

[Evo][Хак] PHx нарвался

Достал этот диво-инструмент и вытекающие из его использования чудеса.

Решение не претендует на свежесть взгляда или универсальность. В моем случае оно работает.


( Читать дальше )

[REVO] getResources и tvFilters и операторы '==', '!=', '<=', '>=', '<>', '>', '<', '='

Вчера вечером, был пост, где человек хочет отфильтровать по оператору '<>'. Казалось, всё просто, но система втыка, не дала свой результат. Меня стала мучить мысля… что, не так, вскрыв getResources, я заметил, что в tvFilters '==' — это не оператор, а разделитель.

( Читать дальше )

Заставляем eForm исполнять сниппеты в шаблоне формы

Ситуации, когда требуется вывести какой-либо select в шаблон формы eForm заполнив его данными из базы нередки. Стандартный способ, описанный в документации к eForm — использование &eformOnBeforeFormParse и последующие пляски с бубном.
Если просто вставить вызов сниппета в код формы, то сниппет будет интерпретирован уже после того, как eForm разберет шаблон, и он не будет учтен.

Мне совершенно неочевидно, почему разработчики eForm не позволили использовать шаблонизатор modx для создания формы, но, как оказалось, мы легко можем сделать это сами.


( Читать дальше )

PlusCatalog - микро-каталог "на коленке" [Evo]

1. Постановка задачи.

Для одного из сайтов понадобилось создавать ресурсы из 2-3 строк текста + фото. Количество таких ресурсов может в перспективе стать запредельным. Использовать для хранения этих данных таблицу в БД modx я посчитал слишком расточительным, да и дерево документов — не резиновое.

Единственно возможным вариантом является хранить эти записи в отдельной таблице в БД. Структуру таблицы можно задать именно такую, которая нужна. Для записи данных в таблицу, а также для их правки/удаления, можно использовать модуль.

Однако, сам по себе сайт для редактора получился достаточно простым и логичным. Я ощутил, что не имею морального права заставлять пользователя часть материалов добавлять через модуль, а часть — через документы modx. Следовательно, нужен интерфейс для работы с внешней таблицей, причем этот интерфейс должен разместиться прямо в дереве документов.



( Читать дальше )

Определения браузера

Иногда, (в данной ситуации у меня возникла необходимость) нужно вывесть картинку или любой тег в зависимости от версии браузера. В данный момент мне нужно было вывести в IE6 картинку без тени. Можно было имено для ослика 6 написать, но написал более расширенный снипет, может кому пригодиться.
Допустим хотим вывести картинку logo.png, а если IE6 то logo_ie6.png. Демо. — логотип

( Читать дальше )

Поиск в AjaxSearch по словосочетанию

Есть на сайте небольшой каталог, реализованных в виде документов.
Требовалось сделать поиск, чтобы по фразе «стол 7 футов» он действительно искал только столы 7 футов.
При уменьшении минимальной длины слова с 3 до 1 и режиме поиска allwords выводит очень много не релевантных данных, например «Стол / пирамида „Grace“ 12 футов (орех пекан)», а цифра 7 в цене нашлась или еще где (поиск идет по pagetitle и content).
Т.е. в данном случае слово «футов» это специальных случай и при встрече в поиске нужно заставить AjaxSearch воспринимать часть строки "%размер% футов" как одно слово, а не 2.

Решение простое. Нужно сделать динамический фильтр, если в поиске встречается слово «футов» (например 7 футов), то исключить все документы, где в pagetitle не встречается «7 футов». Для этого создадим сниппет ASFilter:

<?php
$SearchString = isset($_REQUEST['search'])?$_REQUEST['search']:'';
$result = '';
if ($SearchString!='') {
  $SearchString = mb_strtolower($SearchString,$modx->config['modx_charset']);
  $matches = array();
  if (preg_match('/\S+\s+футов/',$SearchString,$matches)) {
    $SizeString = $matches[0];
    $result='pagetitle,'.$SizeString.',9';
  }
}
return $result;
?>


И вставить его в вызов AjaxSearch в параметр filter

[!AjaxSearch? .... &filter=`[!ASFilter!]`!]


Теперь при поиске «стол 7 футов» ищет только столы 7 футов. Таким способом можно добавить и другие специальные слова.