Come posso visualizzare programmaticamente un blocco?


34

Sto sviluppando un sito usando Drupal 8 beta-14. Ho creato un blocco di visualizzazione di termini diversi e ora voglio visualizzarlo utilizzando il codice. Come posso visualizzarlo programmaticamente? Lo facevo in Drupal 7 usando questo codice ma sono confuso su Drupal 8.

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

Risposte:


70

Esistono due tipi di blocchi e il metodo di rendering dei due è leggermente diverso:

Blocchi di contenuto

I blocchi di contenuto sono blocchi creati nell'interfaccia. Sono molto simili a strutture di dati configurabili dei nodi, con campi ecc. Se si desidera eseguire il rendering di uno di questi, è possibile fare ciò che si farebbe normalmente con le entità, caricarle e renderle con il generatore di viste:

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

Blocchi plugin

I blocchi possono anche essere plug-in, definiti in vari moduli. Un esempio potrebbe essere il blocco del pangrattato. Se si desidera renderizzarli, sarà necessario utilizzare il gestore plug-in di blocco.

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

Configurare le entità

Condivisi per i due tipi sono blocchi, che una volta inseriti in una regione, si creerà un'entità di configurazione che ha tutte le impostazioni per il blocco. In alcuni casi sarà più utile gestire le entità di configurazione. Poiché lo stesso blocco può essere posizionato in più aree con e con diversa configurazione, può diventare più complicato utilizzando le entità di configurazione del blocco. La cosa bella è che potresti voler rendere un blocco con una configurazione specifica, la cosa brutta è che gli ID di configurazione possono cambiare facendo un casino con l'interfaccia, quindi il codice potrebbe finire per non funzionare dopo aver permesso agli utenti di usare l'interfaccia del blocco.

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

2
La domanda non specifica se si tratta del rendering di un'entità di configurazione del blocco (un posizionamento di blocco preconfigurato) o di un plug-in di blocco con configurazione codificata. Il che ha senso perché quella differenza non esiste in 7.x. Questo è più flessibile perché l'altro in realtà richiede un blocco specifico che deve essere inserito in un determinato tema e regione. Tuttavia, non dovresti mai crearli a mano. Usa il metodo createInstance () del gestore plug-in a blocchi per quello con l'ID plug-in, dove puoi anche fornire un array $ configuration ...
Berdir

2
Inoltre, potresti considerare di chiamare prima il metodo access () nel caso in cui l'accesso al blocco sia limitato, ad esempio, a una determinata autorizzazione da quel blocco. Puoi migliorare un po 'la tua risposta al riguardo? Può diventare una risorsa utile quindi :)
Berdir,

1
@Berdir È passato un po 'di tempo, ma alla fine sono riuscito a migliorare la risposta. Con tutta la cache in corso, l'utilizzo diretto del plugin è probabilmente utile solo in situazioni limitate.
googletorp

4
Il rovescio della medaglia con l'utilizzo del gestore plug-in di blocco createInstance () è che l'array di rendering risultante non viene eseguito tramite il tema del blocco, quindi non è possibile utilizzare il blocco - nomepile.twig.html, ad esempio. L'alternativa è creare un blocco per il tuo tema, ma lasciarlo disabilitato, quindi nel tuo codice fai: `` $ block = \ Drupal \ block \ Entity \ Block :: load ('myblock'); $ build = \ Drupal :: entityManager () -> getViewBuilder ('block') -> view ($ block); ``
joachim,

1
No - Un'altra tana di coniglio. Il codice per il blocco del contenuto è bianco (con il famigerato "Il sito web ha riscontrato un errore imprevisto. Riprova più tardi.") Il secondo si avvicina - Ma visualizza un messaggio criptico sul blocco mancante o qualcosa del genere ... (che non è è vero perché sto tentando un blocco di sistema - alimentato dalla cosa drupal).
mare26.2

16

Per visualizzare solo il tuo blocco nei tuoi modelli con preelaborazione, il modo migliore è

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

E nel tuo page.html.twigo node.html.twigo xxx.html.twigusa la tua variabile My_region in questo modo:

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

E in un array renderizzabile (modulo personalizzato), ad esempio, in un controller personalizzato in 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,
      );
}

utilizzando drupal_rendernon è utile poiché Drupal assume già il rendering in D8 e questo è obsoleto . Dovresti usare \Drupal::service('renderer')->renderRoot()invece.

È un po 'pesante, è meglio utilizzare il sistema di area massima e non aggiunge il blocco di carico dal preprocesso. Nel caso di utilizzo di un controller nei tuoi moduli questo sembra un uso giustificato.


L'implementazione di questo controller è esattamente quello che stavo cercando. Grazie!
Mrweiner,

Sono interessato a questa implementazione del controller per un caso d'uso simile di cui mi occupo. Ma non riesco a trovare alcuna documentazione sulla element-contentproprietà in un array di rendering. Sai dove è documentato?
Eria,

Non so perché, ma \Drupal\block\Entity\Block::loadnon restituisce un blocco per tutto il tempo. Restituisce qualcosa solo se il blocco che carico è inserito nella vista nel layout del blocco . Se non viene inserito, restituisce null.
Arthur Attout,

Questa risposta dovrebbe essere aggiornata per l'uso\Drupal::entityTypeManager()->getViewBuilder('block')->view($block);
Ryan Hartman,

6

Oltre alla risposta principale ... Se si desidera eseguire il rendering di un blocco da una vista, potrebbe essere necessario fare le cose in modo leggermente diverso.

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

(nome visualizzato ad es. -> blocco_1)

Dal momento che lo passeremo al ramoscello, non è necessario eseguire il rendering (utilizzando il servizio di rendering).

Quindi puoi semplicemente passarlo come variabile al ramoscello (per questo esempio, è il ritorno di un controller):

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

nel tuo modulo hai bisogno di un hook_theme () per la tua variabile:

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

E infine nel tuo modello di ramoscello:

{{ your_variable }}

5

Avevo bisogno di ottenere l'HTML di un blocco personalizzato e ottenerlo usando:

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

print $d->__toString();

1
Avevo bisogno di aggiungerlo a un array di rendering e lì ha funzionato senza __toString().
leymannx,

1
È importante ricordare che almeno un blocco deve essere posizionato nella regione "Blocchi disabilitati". O qualsiasi altra regione attiva.
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));

Se possibile, dovresti evitare di utilizzare drupal_rendero il servizio di rendering. drupal_renderè deprivato ma ritirare un rendering di un array con il contenuto renderizzato è piuttosto male, dovresti $block_contentinvece tornare , l'array di rendering può essere modificato prima del rendering effettivo e dovresti lasciare che Drupal esegua il rendering quanto più posabile o facendolo da solo.
googletorp

Funzionerà solo se il blocco è già posizionato sulla pagina attraverso il layout del blocco.
Hugronaphor,

1

Fondamentalmente, ci sono due tipi di rendering.

  1. Quando esiste un'istanza esistente del blocco nel layout. il blocco può essere reso in ramoscello usando il preprocesso come

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

  2. Non ci sono istanze o configurazioni per il blocco. Quindi nel preprocessore, dobbiamo creare l'istanza, creare il blocco e quindi renderizzarlo

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


0

Sembra che questo funzioni per i blocchi di plugin ..

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

-2

Ottieni l'output del blocco:

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

E quindi puoi restituire l'output in diversi modi:

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

o:

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

\Drupal::service ('renderer')->render ($block_content)può essere fatto come drupal_render ($block_content)Tuttavia quest'ultimo è deprecato in Drupal 8.
olegiv

Se possibile, dovresti evitare di utilizzare drupal_rendero il servizio di rendering. drupal_renderè deprivato ma ritirare un rendering di un array con il contenuto renderizzato è piuttosto male, dovresti $block_contentinvece tornare , l'array di rendering può essere modificato prima del rendering effettivo e dovresti lasciare che Drupal esegua il rendering quanto più posabile o facendolo da solo. Ciò che restituisci deve essere reso di nuovo, il che rende inutile il rendering effettivo
googletorp

-2

Sulla base della mia ricerca, potresti basare il codice su Come rendere un blocco a livello di codice in drupal 8 . Potresti anche cambiare

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

in qualcosa di semplice come:

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

per collegarlo, ad esempio, alla variabile di ritorno di una pagina.


Se possibile, dovresti evitare di utilizzare drupal_rendero il servizio di rendering. drupal_renderè deprivato ma ritirare un rendering di un array con il contenuto renderizzato è piuttosto male, dovresti $block_contentinvece tornare , l'array di rendering può essere modificato prima del rendering effettivo e dovresti lasciare che Drupal esegua il rendering quanto più posabile o facendolo da solo.
googletorp

Hai ragione. Questa non è la soluzione consigliata e più flessibile.
Leolando Tan,

Il tuo link è morto "Come rendere un blocco ..."
sea26.2
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.