Переопределить значения выводимых полей во views, в соответствии с логикой, написанной в php

Аватар пользователя engenes engenes 28 января в 7:42

В 7 Drupal, я писал всю логику прямо в шаблоне вьюса, в шаблоне полей переопределял их значение.
И в самом шаблоне делал необходимые запросы к базе и сравнивал с данными во вьюсе а потом уже менял значения полей в зависимости от условий. И меня это ни сколько не смущало, все работало и не ломалось.

Но в 8 Drupal twig и в него данные приходят уже готовые, остается только сделать вставки в нужных местах.
Вопрос: как в Drupal 8, изменять данные вьюса до того как они приетят в шаблон, какой хук использовать?
попробовал <?php  functionhook_views_pre_render(ViewExecutable $view)  ?>, а чтобы изучить содержимое переменной $view, распечатывал ее через

<?php 
 drm
($view)  ?>

.
Проблема в том что переменная распечатывается один раз пока не обновишь страницу.
Сама переменная является большим массивом с данными, наверняка есть какие-то дополнительные методы, для того чтобы извлечь значения полей, фильтров и других параметров из этого массива, а потом записать их обратно, потому что напрямую по цепочке массива я до них дойти так и не смог.
На этом шаге полный тупик, не понял куда двигаться.

Сейчас только изучаю D8, но по опыту работы с 7 знаю, что переопределять поля менять структуру даных в зависимости от условий требуется практически в каждом проекте.

Лучший ответ

Аватар пользователя marassa marassa 28 января в 19:08

может быть вы знаете как это же сделать и использованием api?

Вот в качестве примера кусок работающего кода, цинично модифицирующего массив результатов:

/**
 * Implements hook_views_pre_render().
 */

function MODULE_views_pre_render(Drupal\views\ViewExecutable $view) {
  if ($view->id() !== 'photo_slideshow' || !in_array($view->current_display, ['photo_gallery', 'artist_gallery', 'user_gallery'])) return;

/* debug($view->result[0], 'debug'); */

  $unique_uuids = $new_view_result = [];
  $new_row_index = 0;

  // Loop through results and filter out duplicate results.
  foreach ($view->result as $row) {
    // Use UUID so this works for all entities
    $uuid = $row->_entity->uuid();
    if (!in_array($uuid, $unique_uuids)) {
      $row->index = $new_row_index;
      $new_view_result[] = $row;
      $unique_uuids[] = $uuid;
      $new_row_index++;
    }
  }

  // Replace $view->result with new array. Apparently views requires sequentially keyed
  // array of results instead of skipping keys (e.g. 0, 2, 4, etc), so we can't just
  // unset the duplicates.
  $view->result = $new_view_result;

  // Update the view index to match the new number of rows.
  $view->total_rows = $new_row_index;

  if ( $view->total_rows > 8) return;
  $view->field['field_picture']->options['settings']['photoswipe_node_style'] = /* $view->total_rows > 1 ? */ 'large_gallery_thumbnail' /* : '' */;

}

Комментарии

Аватар пользователя marassa marassa 28 января в 8:09

engenes wrote:
переопределять поля менять структуру даных в зависимости от условий требуется практически в каждом проекте

А можно хоть один конкретный пример из жизни, чтоб понимать о чем речь?

Аватар пользователя engenes engenes 28 января в 8:32

Пример кода сейчас привести не смогу.
Но вот пример из жизни

Допустим у нас сдаются в аренду объекты недвижимости или автомобили, не принципиально.
На этот предмет указана стоимость аренды за сутки.
И если срок аренды больше 7 дней то действует скидка 10%.
Ну и еще какие-то дополнительные условия могут применяться. Например, идти запрос в базу данных, по текущему пользователю, чтобы предоставить ему персональную скидку, если он накопил, какие нибудь баллы, бонусы, достиг какого-нибудь уровня.

Допустим, пользователь через фильтр выбрал даты, с какого по какое число он хочет арендовать предмет.
во вьюсе выводится базовая стоимость аренды в сутки.
Но в шаблон я хочу прокинуть дополнительную переменную в которой будет содержаться расчетная стоимость. То есть цена в сутки умноженная на количество дней, а так же с проверкой на условие: больше или меньше 7 дней.

Аватар пользователя marassa marassa 28 января в 8:51
1

Это всё легко делается прямо в админке вьюс через перезапись полей и "твиг-арифметику". Одной из наиболее мощных (и наиболее тщательно скрытых) возможностей вьюс является то, что при перезаписи полей можно пользоваться всей мощью языка твиг, а не только тупой подстановкой одного поля вместо другого.
При формировании вьюса нужно все необходимые для расчетов данные вывести в качестве полей и спрятать. Потом вся логика и расчеты с участием этих скрытых полей делаются прямо в админке путем перезаписи поля с использованием синтаксиса твиг. Просто прочтите доку по твигу или обучающий курс какой-нибудь. Результат гораздо более наглядный и легко сопровождаемый, чем стопитьсот строк спагетти-кода, рассованного по хукам.

Аватар пользователя engenes engenes 28 января в 9:45

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

Не строить же мне полностью всю логику с нуля из за этого, чтобы создать собственный вывод. Когда можно сказать что он уже есть, мне просто его надо видоизменить, пересчитать перезаписать, и т.д

Аватар пользователя marassa marassa 28 января в 19:08

может быть вы знаете как это же сделать и использованием api?

Вот в качестве примера кусок работающего кода, цинично модифицирующего массив результатов:

/**
 * Implements hook_views_pre_render().
 */

function MODULE_views_pre_render(Drupal\views\ViewExecutable $view) {
  if ($view->id() !== 'photo_slideshow' || !in_array($view->current_display, ['photo_gallery', 'artist_gallery', 'user_gallery'])) return;

/* debug($view->result[0], 'debug'); */

  $unique_uuids = $new_view_result = [];
  $new_row_index = 0;

  // Loop through results and filter out duplicate results.
  foreach ($view->result as $row) {
    // Use UUID so this works for all entities
    $uuid = $row->_entity->uuid();
    if (!in_array($uuid, $unique_uuids)) {
      $row->index = $new_row_index;
      $new_view_result[] = $row;
      $unique_uuids[] = $uuid;
      $new_row_index++;
    }
  }

  // Replace $view->result with new array. Apparently views requires sequentially keyed
  // array of results instead of skipping keys (e.g. 0, 2, 4, etc), so we can't just
  // unset the duplicates.
  $view->result = $new_view_result;

  // Update the view index to match the new number of rows.
  $view->total_rows = $new_row_index;

  if ( $view->total_rows > 8) return;
  $view->field['field_picture']->options['settings']['photoswipe_node_style'] = /* $view->total_rows > 1 ? */ 'large_gallery_thumbnail' /* : '' */;

}

Аватар пользователя engenes engenes 28 января в 19:30

До этого хука дошёл, но при попытке распечатать $view->result браузер на рабочем ноутбуке умер.
Значит в правильном направлении, если это можно так назвать, шел

Аватар пользователя marassa marassa 28 января в 19:54

engenes wrote:
при попытке распечатать $view->result браузер на рабочем ноутбуке умер

Там огромные рекурсивные массивы, на попытке их вывести целиком что хочешь умрет. Мне иногда помогают модули Devel и Devel Debug Log, но на некоторых массивах и они бессильны.
Да, вместо $view->result есть смысл попробовать вывести хотя бы $view->result[0], так информации меньше, а строки не сильно друг от друга отличаются.

Аватар пользователя davps davps 28 января в 8:48
1

Оъявите новый вьюмод у сущности.
Во вьюхе, вместо полей, выводите сущность(и) в новом вьюмоде
В препроцессе вьюмода описывайте нужную кастомную логику и результаты передавайте в шаблон
В шаблоне выводите всё что нужно

Аватар пользователя engenes engenes 28 января в 9:30

davps wrote:
Оъявите новый вьюмод у сущности.
В препроцессе вьюмода описывайте нужную кастомную логику и результаты передавайте в шаблон

Какой хук для этого лучше всего подойдет?
как раз и хочется отделить логику от шаблона, чтобы не делать расчеты там, где из быть не должно

но ведь для фильтра вьюса это не подойдет? то есть в шаблон то я не смогу передать данные из фильтра

Аватар пользователя davps davps 28 января в 9:32

Какой хук для этого лучше всего подойдет?

Это легко делается через интерфейс: /admin/structure/display-modes/view

Аватар пользователя engenes engenes 28 января в 9:34

я имел в виду то что вы сказали про препроцесс вьюмода.
Попробую поискать сейчас сам

Аватар пользователя bumble bumble 28 января в 11:47

Понимаю, что Вам этого слышать не хочется, но все это пздц какой говнокоддинг.
Объявите свой форматтер поля, это 1 плагинчик. Там, решайте всю логику.
И это будет работать везде, и в представлениях, и в обычном выводе материала, во всех других местах вывода полей.
Оставьте шаблонам те задачи, которые на них возложены.

Аватар пользователя engenes engenes 28 января в 12:43

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

Ладно тут я еще такой пример привел, но другой пример, когда в зависимости от данных в одной строке, эти данные должны меняться в другой. И это нормально делается если пробежаться по массиву с нужным условием.

Но как получить доступ к массиву элементов выводимых во вьюсе, а тем более как переопределить их значения не пойму.

Вьюс мне нравится тем, что есть массив с которым можно работать, гибкая штука, которую я могу изменять как хочу.

но не пойму как добрать до этого массива в восьмерке.