Как сделать фильтр во Views на несовпадение тегов?

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

Аватар пользователя Max123 Max123 15 ноября 2015 в 21:59

Ломаю голову над схемой - каждая статья на сайте промаркирована одним или более тегами, и пользователи могут задавать себе в профиле теги "черного" и "белого" списков - два поля. Хочется, чтобы материал показывался пользователю, только если он имеет хотя бы один тег из белого списка в профиле пользователя и ни одного из черного.
Я завяз на фильтрах Views. Если белый список сооружается легко, то вот как сделать логику чёрного списка, ломаю голову уже долго. Стандартными средствами через отношения и контекстные фильтры не получается, а через поля PHP там же можно посмотреть только теги пользователя (через global $user), но из фильтра никак не добраться до статей и их тегов. Конструкции $argument, node_load($argument), menu_get_object(), $node, которые гуглятся на эту тему, не дают результата в окне фильтра. Проверял через $s = json_encode(...); drupal_set_message($s);
Как бы сделать проверку во Views на несовпадение тегов профиля пользователя и тегов материала?

Комментарии

Аватар пользователя goodboy goodboy 17 ноября 2015 в 1:57

А если, с черным списком поступить так же, как сделано с белым; а потом применить отрицание (чекбокс "Исключить")?

Аватар пользователя Max123 Max123 17 ноября 2015 в 20:52

Теги от материала можно достать, создав relation, там их два на выбор: Content: поле_с_тегами или Content: Taxonomy terms on node. В первом случае я так понимаю, что эти теги идут одним куском и как их разделить для сравнения, не понимаю.

Во втором случае теги сразу разделяются, причем согласно комментарию там же в интерфейсе "This relationship will cause duplicated records if there are multiple terms", образуют как бы несколько путей сравнения, что ли. Дубликаты потом можно объединить с помощью галки "use aggregation". Так вот, в этом втором случае, при наличии среди тегов хотя бы одного подходящего один или несколько "путей" появляются в результатах, потом объединяются в одну запись агрегацией и всё замечательно. Но если в контекстном фильтре поставить галку "exclude", то этот фильтр будет работать отдельно в каждом пути и отрицание будут только в ветках, совпадающие с черным списком, а если есть теги нейтральные, не из черного списка, то они пройдут, агрегируются и в результате в выводе будет материал.

Аватар пользователя goodboy goodboy 18 ноября 2015 в 15:32

Хорошо, а если зайти с другой стороны. Вот у вас есть вьюв, допустим articles. Можно же представить его неявно как articles/белый_список_пользователя/черный_список_пользователя, пусть для конкретного пользователя это будет выглядеть как articles/1+2+5/12+15+17. (Пусть белый список будет до 10, а черные - после). Т.е. Связи(Relations) не используются, а делаются 2 контекстных фильтра, второй с "Исключить". Значения можно получать в "Если значения фильтра НЕТ в URL" - "Передать значение по умолчанию" - "PHP-код" при помощи user_load(). Решение не очень изящное, но давайте попробуем.

Я попробовал - так не получилось. Попробуйте не через контекстные, а через обычные фильтры. Там добавляются LEFT JOIN, а не WHERE как в контекстных.