Як я можу програмно відображати блок?


33

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

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

Відповіді:


69

Існує два типи блоків, і метод їх надання трохи відрізняється:

Блоки вмісту

Блоки вмісту - це блоки, які ви створюєте в інтерфейсі. Вони дуже схожі на вузли, що налаштовуються структурами даних, з полями тощо. Якщо ви хочете вивести одне з них, ви можете робити те, що зазвичай робите з сутностями, завантажуйте їх і надайте їх конструктору перегляду:

$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.twig.html. Альтернативою є створення блоку для вашої теми, але залиште його відключеним, а потім у своєму коді зробіть: `` `$ block = \ Drupal \ block \ Entity \ Block :: load ('myblock'); $ build = \ Drupal :: entitManager () -> getViewBuilder ('блок') -> view ($ блок); `` `
Йоахім

1
Ніп - Ще одна кроляча нора. Код білих екранів блоку вмісту (із сумнозвісною "Веб-сайт зіткнувся з несподіваною помилкою. Будь ласка, спробуйте пізніше.") Другий наближається. Але відображається загадкове повідомлення про відсутність блоку чи щось таке ... (що не Неправда, тому що я намагаюсь блокувати систему - на базі Drupal).
море26.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)

Оскільки ми збираємося передати його на гілочку, нам не потрібно рендерінг (використовуючи послугу візуалізації).

Таким чином, ви можете просто передати його як змінну до гілочки (для цього прикладу повернення контролера):

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

у вашому модулі вам потрібна гачка_теми () для вашої змінної:

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

Це буде працювати лише в тому випадку, якщо блок вже розміщений на сторінці через макет блоку.
хугронафор

1

В основному, існує два типи візуалізації.

  1. Коли в макеті є наявний примірник блоку. блок може бути рендерирован у гілочку, використовуючи попередню обробку як

    $ block = Блок :: load ('BLOCK_ID'); $ змінних ['social_links'] = \ Drupal :: entitTypeManager () -> getViewBuilder ('блок') -> перегляд ($ блок);

  2. Для блоку немає примірника чи конфігурації. Тоді в препроцесорі нам потрібно створити екземпляр, скласти блок і потім вивести його

    $ block_manager = \ Drupal :: service ('plugin.manager.block'); $ config = []; $ plugin_block = $ block_manager-> createInstance ('farmjournal_social_sharing', $ config); $ render = $ plugin_block-> build (); $ змінних ['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)проте остання застаріла в Друпалі 8.
Олегів

Якщо можливо, вам слід уникати використання 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

Ти правий. Це не рекомендоване і найскладніше рішення.
Леоландо Тан

Ваше посилання мертве "Як надати блок ..."
море26.2
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.