Как я могу программно отобразить блок?


34

Я занимаюсь разработкой сайта с использованием Drupal 8 beta-14. Я создал блок просмотра различных терминов, и теперь я хочу отобразить его с помощью кода. Как я могу отобразить это программно? Раньше я делал это в Drupal 7, используя этот код, но я запутался в Drupal 8.

$block = module_invoke('block', 'block_view', '4');
$text_block = render($block['content']);

Ответы:


70

Существует два типа блоков, и метод их рендеринга немного отличается:

Блоки контента

Блоки контента - это блоки, которые вы создаете в интерфейсе. Они очень похожи на настраиваемые узлами структуры данных, с полями и т. Д. Если вы хотите визуализировать одну из них, вы можете делать то, что вы обычно делаете с сущностями, загружать их и визуализировать их с помощью построителя представлений:

$bid = ??? // Get the block id through config, SQL or some other means
$block = \Drupal\block_content\Entity\BlockContent::load($bid);
$render = \Drupal::entityTypeManager()->
  getViewBuilder('block_content')->view($block);
return $render;

Блоки плагинов

Блоки также могут быть плагинами, определенными в различных модулях. Примером может служить блок с хлебными крошками. Если вы хотите отрендерить их, вам нужно будет использовать менеджер блочных плагинов.

$block_manager = \Drupal::service('plugin.manager.block');
// You can hard code configuration or you load from settings.
$config = [];
$plugin_block = $block_manager->createInstance('system_breadcrumb_block', $config);
// Some blocks might implement access check.
$access_result = $plugin_block->access(\Drupal::currentUser());
// Return empty render array if user doesn't have access.
// $access_result can be boolean or an AccessResult class
if (is_object($access_result) && $access_result->isForbidden() || is_bool($access_result) && !$access_result) {
  // You might need to add some cache tags/contexts.
  return [];
}
$render = $plugin_block->build();
// In some cases, you need to add the cache tags/context depending on
// the block implemention. As it's possible to add the cache tags and
// contexts in the render method and in ::getCacheTags and 
// ::getCacheContexts methods.
return $render;

Конфигурация сущностей

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

$block = \Drupal\block\Entity\Block::load('config.id');
$render = \Drupal::entityTypeManager()
  ->getViewBuilder('block')
  ->view($block);
return $render;

2
Вопрос не указывает, касается ли это рендеринга объекта конфигурации блока (предварительно настроенное размещение блока) или плагина блока с жестко заданной конфигурацией. Что имеет смысл, потому что эта разница не существует в 7.x. Это более гибко, потому что другой фактически требует определенного блока, который должен быть помещен в данную тему и регион. Тем не менее, вы никогда не должны создавать их вручную. Для этого используйте метод createInstance () менеджера плагинов блоков с идентификатором плагина, где вы также можете
указать

2
Кроме того, вы можете захотеть сначала вызвать метод access (), если доступ к блоку ограничен, например, определенным разрешением этого блока. Можете ли вы улучшить свой ответ немного об этом? Может стать полезным ресурсом тогда :)
Бердир

1
@Berdir Это было некоторое время, но я наконец нашел способ улучшить ответ. С учетом всего того, что происходит при кэшировании, использование плагина напрямую возможно только в ограниченных ситуациях.
googletorp

4
Недостатком использования менеджера плагинов блоков createInstance () является то, что результирующий массив рендеринга не проходит через тематику блока, поэтому вы не можете использовать, например, blockname.bwname.twig.html. Альтернативой является создание блока для вашей темы, но оставьте его отключенным, а затем в своем коде выполните: `` `$ block = \ Drupal \ block \ Entity \ Block :: load ('myblock'); $ build = \ Drupal :: entityManager () -> getViewBuilder ('block') -> view ($ block); `` `
Иоахим

1
Нет - Еще одна кроличья нора. Код для белых экранов блока контента (с печально известной «На веб-сайте обнаружена непредвиденная ошибка. Пожалуйста, повторите попытку позже.») Второй подход ближе - но отображает загадочное сообщение об отсутствии блока или о чем-то ... (что не это правда, потому что я пытаюсь системный блок - питание от друпала).
sea26.2

16

Для отображения только вашего блока в ваших шаблонах с предварительной обработкой лучше всего

$block = \Drupal\block\Entity\Block::load('my_block_id');
$variables['My_region'] = \Drupal::entityManager()
          ->getViewBuilder('block')
          ->view($block);

И в вашей page.html.twigили node.html.twigили xxx.html.twigиспользуйте вашу переменную My_region, как это:

{% if page.My_region %}
    {{ page.My_region }}
{% endif %}

И в рендеринг массив (пользовательский модуль), например, в контроллер, пользовательский в content ():

public function content() {
    $block = \Drupal\block\Entity\Block::load('my_block_id');
    $block_content = \Drupal::entityManager()
      ->getViewBuilder('block')
      ->view($block);

          return array(
        '#type' => 'container',
        '#attributes' => array(
          'class' => array("Myclass"),
        ),
        "element-content" => $block_content,
        '#weight' => 0,
      );
}

С помощью drupal_renderбесполезен, поскольку Drupal уже предполагает рендеринг в D8, и это устарело . Вы должны использовать \Drupal::service('renderer')->renderRoot()вместо этого.

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


Эта реализация контроллера именно то, что я искал. Благодарность!
Mrweiner

Я заинтересован в реализации этого контроллера для аналогичного варианта использования, с которым я имею дело. Но я не могу найти документацию о element-contentсвойствах в массиве рендеринга. Вы знаете, где это задокументировано?
Эрия

Я не знаю почему, но \Drupal\block\Entity\Block::loadне возвращает блок все время. Он возвращает что-то, только если загруженный блок помещается в представление в макете блока . Если это не помещено, это возвращает нуль.
Артур Аттут

Этот ответ должен быть обновлен для использования\Drupal::entityTypeManager()->getViewBuilder('block')->view($block);
Райан Хартман

6

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

$view = views_embed_view('my_view_name', 'my_display_name');

(отображаемое имя, например -> block_1)

Так как мы собираемся передать его ветке, нам не нужно рендерить (используя сервис рендеринга).

Таким образом, вы можете просто передать его как переменную twig (для этого примера это возврат контроллера):

return [
  ['description' => [
    '#theme' => 'your_theme_hook',
    '#your_variable => $view
  ]
]

в вашем модуле вам нужна hook_theme () для вашей переменной:

function hook_theme($existing, $type, $theme, $path) {
  return array(
    'your_theme_hook' => array(
      'variables' => [
        'your_variable' => NULL,
      ]
    )
  )
}

И, наконец, в вашем шаблоне ветки:

{{ your_variable }}

5

Мне нужно было получить HTML-код пользовательского блока и получить его с помощью:

$con = \Drupal\block\BlockViewBuilder::lazyBuilder('bartik_search', 'full');
$d   = \Drupal::service('renderer')->renderPlain($con);

print $d->__toString();

1
Мне нужно было добавить его в массив визуализации, и там он работал без __toString().
Leymannx

1
Важно отметить, что хотя бы один блок нужно разместить в области «Блокированные блоки». Или любой другой активный регион.
leymannx

1
// You need a block_id! to get it just click configure in the desire block and you'll get url like this /admin/structure/block/manage/bartik_search   the last part of the parameter is the block id
$block = \Drupal\block\Entity\Block::load('bartik_search');
$block_content = \Drupal::entityManager()
  ->getViewBuilder('block')
  ->view($block);

return array('#markup' => \Drupal::service('renderer')->renderRoot($block_content));

Если возможно, вам следует избегать использования drupal_renderили оказания услуг. drupal_renderограничен, но получение рендеринга массива с визуализированным содержимым довольно плохо, вы должны $block_contentвместо этого вернуть , массив рендеринга может быть изменен перед фактическим рендерингом, и вы должны позволить Drupal делать рендеринг настолько, насколько это возможно, или делать это самостоятельно.
googletorp

Это сработает только в том случае, если блок уже размещен на странице через макет блока.
hugronaphor

1

В основном, есть два типа рендеров.

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

    $ block = Block :: load ('BLOCK_ID'); $ variable ['social_links'] = \ Drupal :: entityTypeManager () -> getViewBuilder ('block') -> view ($ block);

  2. Там нет экземпляра или конфигурации для блока. Затем в препроцессоре нам нужно создать экземпляр, построить блок и затем отобразить его.

    $ block_manager = \ Drupal :: service ('plugin.manager.block'); $ config = []; $ plugin_block = $ block_manager-> createInstance ('farmjournal_social_sharing', $ config); $ render = $ plugin_block-> build (); $ variable ['farmjournal_social_sharing'] = render ($ render);


0

Кажется, это работает для плагинов блоков.

$block = \Drupal\block\Entity\Block::load('some_block_id_3');
  $pluin = $block->getPlugin();
  $build = $pluin->build();
  $build['#weight'] = 4;
  $form['block'] = $build;

-2

Вы получаете блок вывода:

$block = \Drupal\block\Entity\Block::load ('my_bock_id');
$block_content = \Drupal::entityManager ()->
  getViewBuilder ('block')->
  view ($block);

И тогда вы можете вернуть вывод разными способами:

return array (
    '#type' => 'container',
    'element-content' => $block_content
);

или:

return ['#markup' => \Drupal::service ('renderer')->render ($block_content)];

\Drupal::service ('renderer')->render ($block_content)может быть сделано как drupal_render ($block_content)Однако последний устарел в Drupal 8.
olegiv

Если возможно, вам следует избегать использования drupal_renderили оказания услуг. drupal_renderограничен, но получение рендеринга массива с визуализированным содержимым довольно плохо, вы должны $block_contentвместо этого вернуть , массив рендеринга может быть изменен перед фактическим рендерингом, и вы должны позволить Drupal делать рендеринг настолько, насколько это возможно, или делать это самостоятельно. То, что вы возвращаете, должно быть снова обработано, что делает бессмысленным рендеринг
googletorp

-2

Основываясь на моих исследованиях, вы можете основать код из Как программно визуализировать блок в Drupal 8 . Вы также можете изменить

return array('#markup' => \Drupal::service('renderer')->renderRoot($block_content));

в нечто такое простое, как:

$output .= \Drupal::service('renderer')->renderRoot($block_content);

прикрепить его, например, в переменную возврата страницы.


Если возможно, вам следует избегать использования drupal_renderили оказания услуг. drupal_renderограничен, но получение рендеринга массива с визуализированным содержимым довольно плохо, вы должны $block_contentвместо этого вернуть , массив рендеринга может быть изменен перед фактическим рендерингом, и вы должны позволить Drupal делать рендеринг настолько, насколько это возможно, или делать это самостоятельно.
googletorp

Вы правы. Это не рекомендуемое и самое гибкое решение.
Леоландо Тан

Ваша ссылка мертва "Как сделать блок ..."
sea26.2
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.