Làm thế nào tôi có thể lập trình một khối?


33

Tôi đang phát triển một trang web bằng Drupal 8 beta-14. Tôi đã tạo một khối xem các thuật ngữ khác nhau và bây giờ tôi muốn hiển thị nó bằng mã. Làm thế nào tôi có thể hiển thị nó theo chương trình? Tôi đã từng làm điều đó trong Drupal 7 bằng cách sử dụng mã này nhưng tôi bối rối về Drupal 8.

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

Câu trả lời:


69

Có hai loại khối và phương thức hiển thị hai khối này hơi khác nhau:

Khối nội dung

Khối nội dung là các khối mà bạn tạo trong giao diện. Chúng giống như các cấu trúc dữ liệu có thể định cấu hình các nút, với các trường, v.v. Nếu bạn muốn kết xuất một trong số đó, bạn có thể làm những gì bạn thường làm với các thực thể, tải chúng và hiển thị chúng bằng trình xây dựng chế độ xem:

$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;

Khối plugin

Các khối cũng có thể là plugin, được xác định trong các mô-đun khác nhau. Một ví dụ có thể là khối bánh mì. Nếu bạn muốn kết xuất những thứ này, bạn sẽ cần sử dụng trình quản lý plugin khối.

$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;

Cấu hình thực thể

Được chia sẻ cho hai loại là các khối, là khi bạn chèn chúng vào một vùng, bạn sẽ tạo một thực thể cấu hình có tất cả các cài đặt cho khối. Trong một số trường hợp, nó sẽ hữu ích hơn khi xử lý các thực thể cấu hình. Vì cùng một khối có thể được đặt ở nhiều vùng với và với cấu hình khác nhau, nên có thể khó sử dụng các thực thể cấu hình khối hơn. Điều tuyệt vời là bạn có thể muốn kết xuất một khối với cấu hình cụ thể, điều tệ là các id cấu hình có thể thay đổi bằng cách làm rối giao diện, do đó mã có thể không hoạt động sau khi cho phép người dùng sử dụng giao diện khối.

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

2
Câu hỏi không chỉ định nếu đó là về kết xuất một thực thể cấu hình khối (vị trí khối được định cấu hình trước) hoặc plugin khối có cấu hình được mã hóa cứng. Điều này có ý nghĩa bởi vì sự khác biệt đó không tồn tại trong 7.x. Điều này linh hoạt hơn bởi vì cái kia thực sự đòi hỏi một khối cụ thể cần được đặt trong một chủ đề và khu vực nhất định. Tuy nhiên, bạn không bao giờ nên tạo chúng bằng tay. Sử dụng phương thức createdInstance () của trình quản lý khối cho điều đó với ID plugin, nơi bạn cũng có thể cung cấp một mảng cấu hình $ ...
Berdir

2
Ngoài ra, bạn có thể muốn xem xét việc gọi phương thức access () trước trong trường hợp truy cập khối bị hạn chế, ví dụ như một sự cho phép nhất định của khối đó. Bạn có thể cải thiện câu trả lời của bạn một chút về điều đó? Có thể trở thành một tài nguyên hữu ích sau đó :)
Berdir

1
@Berdir Đã được một lúc, nhưng cuối cùng tôi cũng tìm cách cải thiện câu trả lời. Với tất cả các bộ nhớ đệm khác nhau đang diễn ra, sử dụng plugin trực tiếp có lẽ chỉ hữu ích trong các tình huống hạn chế.
googletorp

4
Nhược điểm của việc sử dụng trình quản lý plugin blockInstance () là mảng kết xuất kết quả không chạy qua chủ đề khối, vì vậy, bạn không thể sử dụng block - blockname.twig.html, chẳng hạn. Cách khác là tạo một khối cho chủ đề của bạn, nhưng để nó bị vô hiệu hóa, và sau đó trong mã của bạn làm: `` `$ block = \ Drupal \ block \ Entity \ Block :: load ('myblock'); $ build = \ Drupal :: entityManager () -> getViewBuilder ('block') -> view ($ block); `` `
joachim

1
Không - Một lỗ thỏ khác. Mã cho màn hình trắng chặn nội dung (với tiếng xấu "Trang web gặp lỗi không mong muốn. Vui lòng thử lại sau.") Lần thứ hai tiến gần hơn - Nhưng hiển thị thông báo khó hiểu về khối bị thiếu hoặc một cái gì đó ... (không phải là 'đúng vì tôi đang thử một khối hệ thống - được cung cấp bởi thứ drupal).
biển 26.2

16

Để chỉ hiển thị khối của bạn trong các mẫu của bạn với tiền xử lý, cách tốt nhất là

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

Và trong của bạn page.html.twighoặc node.html.twighoặc xxx.html.twigsử dụng biến My_region của bạn như thế này:

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

Và trong mảng kết xuất (mô-đun tùy chỉnh) bằng ví dụ vào bộ điều khiển tùy chỉnh trong nội dung ():

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,
      );
}

Sử dụng drupal_renderkhông hữu ích vì Drupal đã giả sử kết xuất trong D8 và điều này không được chấp nhận . Bạn nên sử dụng \Drupal::service('renderer')->renderRoot()thay thế.

Nó hơi nặng, tốt hơn là sử dụng hệ thống diện tích tối đa và không thêm khối tải từ tiền xử lý. Trong trường hợp sử dụng bộ điều khiển trong các mô-đun của bạn, điều này có vẻ như là một cách sử dụng hợp lý.


Điều khiển thực hiện này là chính xác những gì tôi đang tìm kiếm. Cảm ơn!
Mrweiner

Tôi quan tâm đến việc triển khai bộ điều khiển này cho một trường hợp sử dụng tương tự mà tôi đang xử lý. Nhưng tôi không thể tìm thấy bất kỳ tài liệu nào về element-contenttài sản trong một mảng render. Bạn có biết nó được ghi lại ở đâu không?
Eria

Tôi không biết tại sao, nhưng \Drupal\block\Entity\Block::loadkhông trả lại một khối mọi lúc. Nó chỉ trả về một cái gì đó nếu khối tôi tải được đặt trong chế độ xem theo bố cục khối . Nếu nó không được đặt, nó sẽ trả về null.
Arthur Attout

Câu trả lời này nên được cập nhật để sử dụng\Drupal::entityTypeManager()->getViewBuilder('block')->view($block);
Ryan Hartman

6

Ngoài câu trả lời hàng đầu ... Nếu bạn muốn kết xuất một khối từ chế độ xem, bạn có thể phải thực hiện mọi thứ khác đi một chút.

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

(tên hiển thị, ví dụ -> block_1)

Vì chúng tôi sẽ chuyển nó sang twig, chúng tôi không cần kết xuất (sử dụng dịch vụ kết xuất).

Vì vậy, bạn có thể chuyển nó dưới dạng một biến thành twig (ví dụ này là sự trở lại của Bộ điều khiển):

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

trong mô-đun của bạn, bạn cần một hook_theme () cho biến của mình:

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

Và cuối cùng trong mẫu twig của bạn:

{{ your_variable }}

5

Tôi cần lấy HTML của một khối tùy chỉnh và sử dụng nó bằng cách sử dụng:

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

print $d->__toString();

1
Tôi cần phải thêm nó vào một mảng render và nó hoạt động mà không cần __toString().
leymannx

1
Điều quan trọng cần đề cập là một khối ít nhất cần phải được đặt trong khu vực "Khối bị vô hiệu hóa". Hoặc bất kỳ khu vực hoạt động khác.
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));

Nếu có thể, bạn nên tránh sử dụng drupal_renderhoặc dịch vụ kết xuất. drupal_renderbị lỗi nhưng việc giữ lại một mảng kết xuất với nội dung được hiển thị khá tệ, bạn nên trả về$block_content thay vào đó , mảng kết xuất có thể được thay đổi trước khi kết xuất thực tế và bạn nên để Drupal thực hiện kết xuất nhiều như thay thế hoặc tự thực hiện.
googletorp

Điều này sẽ chỉ hoạt động nếu khối đã được đặt trên trang thông qua bố trí khối.
hugronaphor

1

Về cơ bản, có hai loại render.

  1. Khi có một thể hiện hiện có của khối trong bố trí. khối có thể được kết xuất trong twig bằng cách sử dụng tiền xử lý như

    $ block = Block :: tải ('BLOCK_ID'); $ biến ['social_links'] = \ Drupal :: entityTypeManager () -> getViewBuilder ('block') -> view ($ block);

  2. Không có ví dụ hoặc cấu hình cho khối. Sau đó, trong bộ tiền xử lý, chúng ta cần tạo cá thể, xây dựng khối và sau đó kết xuất nó

    $ block_manager = \ Drupal :: service ('plugin.manager.block'); $ config = []; $ plugin_block = $ block_manager-> createInstance ('farmjournal_social_shishing', $ config); $ render = $ plugin_block-> build (); $ biến ['farmjournal_social_shared'] = render ($ render);


0

Có vẻ như điều này hoạt động cho các khối plugin ..

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

-2

Bạn nhận được khối đầu ra:

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

Và sau đó bạn có thể trả lại đầu ra theo những cách khác nhau:

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

hoặc là:

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

\Drupal::service ('renderer')->render ($block_content)có thể được thực hiện như drupal_render ($block_content)Tuy nhiên sau đó không được chấp nhận trong Drupal 8.
olegiv

Nếu có thể, bạn nên tránh sử dụng drupal_renderhoặc dịch vụ kết xuất. drupal_renderbị lỗi nhưng việc giữ lại một mảng kết xuất với nội dung được hiển thị khá tệ, $block_contentthay vào đó bạn nên quay lại , mảng kết xuất có thể được thay đổi trước khi kết xuất thực tế và bạn nên để Drupal thực hiện kết xuất nhiều như thay thế hoặc tự thực hiện. Những gì bạn trả về cần phải được hiển thị lại, điều này làm cho kết xuất thực tế trở nên vô nghĩa
googletorp

-2

Dựa trên nghiên cứu của tôi, bạn có thể dựa vào mã từ Cách kết xuất khối theo chương trình trong drupal 8 . Bạn cũng có thể thay đổi

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

vào một cái gì đó đơn giản như:

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

ví dụ để đính kèm nó vào biến trả về của trang.


Nếu có thể, bạn nên tránh sử dụng drupal_renderhoặc dịch vụ kết xuất. drupal_renderbị lỗi nhưng việc giữ lại một mảng kết xuất với nội dung được hiển thị khá tệ,$block_content thay vào đó bạn nên quay lại , mảng kết xuất có thể được thay đổi trước khi kết xuất thực tế và bạn nên để Drupal thực hiện kết xuất nhiều như thay thế hoặc tự thực hiện.
googletorp

Bạn đúng. Đây không phải là giải pháp được khuyến nghị và linh hoạt nhất.
Leolando Tan

Liên kết của bạn đã chết "Cách kết xuất khối ..."
sea26.2
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.