Отбор по полям подчиненных nodes (Node Relativity)

Главные вкладки

Аватар пользователя kivals kivals 14 ноября 2007 в 12:54

Прошу извинить, если вопрос покажется тривиальным, но ответа не смог найти Sad

Есть nodes типа firm, есть подчиненные им (child nodes) типа firm_clients (естественно - их несколько для каждой родительской)
У типа firm_clients есть поля client, country.

В списке фирм необходимо отобрать только те, у подчиненных элементов которых страна и/или клиент соответсвует указанному фильтру (Exposed Filters) на форме.

Как вариант - я рассматривал возможность динамически подменять параметры фильтра (в Argument Handling Code) - т.е. могу отобрать фирмы например по идентификаторам parent_node, но вот вопрос - как получить список child_nodes в приминением заданных в форме фильтров программно (в коде php)?

Скорее всего - это не единственный вариант решения. С благодарностью рассмотрю другие предложенные варианты!

P.S. Опыт php приличный, опыт drupal - узнал 4 дня назад Smile

Комментарии

Аватар пользователя alexweb alexweb 14 ноября 2007 в 13:28

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

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

Аватар пользователя kivals kivals 14 ноября 2007 в 14:14

Именно так и делал - так и научился менять запросы, код для анализа взят отсюда:
http://www.drupal.ru/node/6954#comment-42870
Я пока поставил на странице фильтры, которые должны работать с типом firm_clients (хотя сам вид отображает типы firm) и вижу вот такой код:

[exposed_filter] => Array
(
        [0] => Array
        (
                [vid] => 1
                [field] => node_data_field_client.field_client_nid_default
                [label] =>
                [optional] => 1
                [is_default] => 0
                [operator] => 0
                [single] => 0
                [position] => 0
                [id] => node_data_field_client.field_client_nid_default
        )

        [1] => Array
        (
                [vid] => 1
                [field] => node_data_field_country.field_country_nid_default
                [label] =>
                [optional] => 1
                [is_default] => 0
                [operator] => 0
                [single] => 0
                [position] => 1
                [id] => node_data_field_country.field_country_nid_default
        )

        [2] => Array
        (
                [vid] => 1
                [field] => term_node_2.tid
                [label] =>
                [optional] => 1
                [is_default] => 0
                [operator] => 0
                [single] => 0
                [position] => 2
                [id] => term_node_2.tid
        )
)

Я планирую по этим фильтрам получить нужные подчиненные ноды, а потом заменить эти фильтры одним, чтобы получить список родителей, но остается вопрос: как в коде получить результаты отбора по этим фильтрам?
нужно что-то типа node_query_by_filter(...);

Аватар пользователя vadbars@drupal.org vadbars@drupal.org 14 ноября 2007 в 15:38

Из непрограммных способов - есть модули views_fusion (делает связку нескольких видов). Описание:"Здесь можно создать связки между двумя видами. Выберите основной вид, который вы хотите использовать, затем выберите второй вид, который будет в \"связке\" с первым. Поля, фильтры и сортировка из связанного вида будет добавлена к первому виду."
Если я правильно понял вашу задачу - может помочь.

Аватар пользователя kivals kivals 14 ноября 2007 в 17:35

Не получается Sad
выдает ошибки:

warning: pg_query() [function.pg-query]: Query failed: ERROR: missing FROM-clause entry for table "nodefamily_parent" LINE 1: ...node_child.nid WHERE (node.type IN ('firm')) AND (nodefamily... ^ in D:\Work\web\drupal\includes\database.pgsql.inc on line 125.
user warning: query: SELECT count(node.nid) FROM node node INNER JOIN nodefamily nodefamily_child ON node.nid = nodefamily_child.child_nid LEFT JOIN node v6node ON nodefamily_child.parent_nid = v6node.nid INNER JOIN nodefamily v6nodefamily_parent ON v6node.nid = v6nodefamily_parent.parent_nid INNER JOIN node v6nf_node_child ON v6nodefamily_parent.child_nid = v6nf_node_child.nid WHERE (node.type IN ('firm')) AND (nodefamily_parent.child_nid = '') AND (v6nf_node_child.type = 'firm') in D:\Work\web\drupal\includes\database.pgsql.inc on line 144.
warning: pg_query() [function.pg-query]: Query failed: ERROR: missing FROM-clause entry for table "nodefamily_parent" LINE 1: ...node_child.nid WHERE (node.type IN ('firm')) AND (nodefamily... ^ in D:\Work\web\drupal\includes\database.pgsql.inc on line 125.
user warning: query: SELECT node.nid, v6node.nid AS v6node_nid FROM node node INNER JOIN nodefamily nodefamily_child ON node.nid = nodefamily_child.child_nid LEFT JOIN node v6node ON nodefamily_child.parent_nid = v6node.nid INNER JOIN nodefamily v6nodefamily_parent ON v6node.nid = v6nodefamily_parent.parent_nid INNER JOIN node v6nf_node_child ON v6nodefamily_parent.child_nid = v6nf_node_child.nid WHERE (node.type IN ('firm')) AND (nodefamily_parent.child_nid = '') AND (v6nf_node_child.type = 'firm') LIMIT 10 OFFSET 0 in D:\Work\web\drupal\includes\database.pgsql.inc on line 144.

сейчас попробую базу на MySQL поднять....

Аватар пользователя kivals kivals 14 ноября 2007 в 18:09

на MySQL без ошибок, но не могу понять как связать элементы Sad
вот здесь: admin/content/nodefamily добавил связь между контентами - а где установить, что нода Компания 1 (типа fc) есть дочерней для ноды Фирма 1 (типа f)?
Сейчас у меня 2 ноды типа f (Фирма 1 и Фирма 2) и 2 ноды типа fc (Компания 1 и Компания 2).
Соответственно - одноименные виды (с фильтром по типу нод)
В admin/build/views/fusion добавил связь между видами: primary view=f; fused view=fc; using=nodefamily relation: parent - child
В итоге у меня для вида f выводится по 2 раза каждая фирма.

Добавил третью компанию - каждая фирма стала по 3 раза выводится...

Аватар пользователя kivals kivals 15 ноября 2007 в 19:00

Разобрался с динамическими фильтрами.
Понадобился дополнительный модуль: Views PHP Filter
Идея такая:
1. В настройке формы первым фильтром ставлю PHP filter в режиме PHP (в режиме списка он у меня почему-то не работал)
2. Следующий фильтр - отбор по родительскому контенту (его я использую если все критерии поиска установлены в режиме "ВСЕ")
3. Остальные - фильтры по подчиненному контенту.

В програмной части:
сохраняю и удаляю первый фильтр из массива:
<?php $filter0=array_shift($view->filter); ?>
сохраняю второй фильтр:
<?php $filter1=array_shift($view->filter); array_unshift($view->filter,$filter1);
// можно и $filter1=$view->filter[0]; - как больше нравится ?>
меняю во втором фильтре контент поиска на подчиненный контент (в моем случае: firm_clients):
<?php $view->filter[0]['value'][0]=$child_node_type; ?>
самая интересная часть - формирую запрос:
<?php $filters=views_get_filter_values();
$info = _views_get_query($view, $args, $filters);
$query = db_rewrite_sql($info['query'], 'node'); ?>
дальше просто - получаю список подчиненных нод, еще один запрос для получения списка родительских нод.
Этот запрос уже вручную - он зависит от того, каким модулем реализовывалась подчиненность. В моем случае (для Node Relativity) это так:
<?php $query = "SELECT parent_nid AS nid FROM {relativity} relativity WHERE (nid IN ($nodes))";
// $nodes - comma separated result of first query, like: "1,2,3" ?>
и результат подставляю в сохраненный фильтр:
<?php $filter0['value'][0]="return array($nodes);"; ?>
оставляем только этот фильтр:
<?php $view->filter=array();
$view->filter[]=$filter0; ?>
на всякий случай - запрос не кешируем:
<?php $view->is_cacheable=0; ?>

Все! <?php return $args; ?>

P.S. некоторые мелочей конкретной реализации я здесь не осветил, как то:
1. Проверка что хоть какой-то фильтр включен
2. Результат если на этапе отбора не получены данные
Важный момент: вызов <?php _views_get_query($view, $args, $filters); ?>меняет $view - так что в случае анализа данных с использованием <?php print_r($view); ?> делайте это после этой функции - получите более полную картину

P.P.S. для использования функций views_*** естественно нужен модуль Views