Embeber componentes de drupal dentro de paragraph de forma transparente al usuario.
01/12/2017 by alvar0hurtad0

Front.id

Muchas veces cuando construimos páginas con paragraphs usamos un modelo basado en tener un tipo de contenido con un campo multivaluado que renderiza componentes. El problema ocurre cuando uno de esos componentes no es un campo en si, si no una referencia a una vista, un formulario, un bloque, etc. Si quieres ver cómo se puede resolver esto de una forma sencilla para los editores sigue leyendo.

Tenemos dos optiones: con site-building y con un poquito de código.

Con site-building.

Esta opción consitiría en poner un campo de tipo referencia, e indicar que vas a hacer referencia a una vista (o lo que sea que queramos embeber):

drupal

El problema en este punto es que cuando el editor cree un paragraph de este tipo, le aparecerán todas las vistas que hayas creado y seguramente se sienta contrariado.

Para solucionar este problema, podemos dar un valor por defecto y eliminar el campo del formulario.

Con código (la preferida del autor)

Para solucionar el mismo problema con un poquito de código podemos crear un paragraph sin ningún campo (o si lo queremos algún texto introductorio, o título, pero sin campo de tipo referencia).

Y ahora viene la idea importante:

Ponemos la vista, formulario o lo que queramos encapsular dentro del paragraph como un extra-field

Para llevar esto a cabo declararíamos un módulo example_front_id y en el fichero example_front_id.module:

<?php

/**
 * @file
 * Primary module hooks for Example Front Id components: contact module.
 */

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;

/**
 * Implements hook_entity_extra_field_info().
 */
function _components_contact_entity_extra_field_info() {
  // Get the service implementing the logic.
  $extra_fields_info = \Drupal::service('example_front_id_components_contact.extrafields');

  return $extra_fields_info->entityExtraFieldInfo();
}

/**
 * Implements hook_ENTITY_TYPE_view().
 */
function example_front_id_components_contact_paragraph_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  // Get the service implementing the logic.
  $extra_fields_info = \Drupal::service('example_front_id_components_contact.extrafields');

  return $extra_fields_info->paragraphView($build, $entity, $display, $view_mode);
}

estamos usando un servicio para encapsular toda la lógica, por lo que debemos declarar el servicio en un fichero llamado example_front_id_components_contact.services.yml:

services:
  example_front_id_components_contact.extrafields:
    class: Drupal\example_front_id_components_contact\ExtraFields
    arguments: ['@entity_type.manager', '@entity.form_builder']

Y definir la clase con su correspondiente interfaz:

<?php
namespace Drupal\example_front_id_components_contact;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
/**
 * Interface ExtraFieldsInterface.
 */
interface ExtraFieldsInterface {
  /**
   * Generates the array of extra fields.
   *
   * @see hook_entity_extra_field_info().
   */
  public function entityExtraFieldInfo();
  /**
   * Hook hook_ENTITY_TYPE_view() implementation.
   *
   * @see hook_ENTITY_TYPE_view().
   */
  public function paragraphView(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode);
}
<?php
namespace Drupal\example_front_id_components_contact;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityFormBuilderInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
 * Class ExtraFields.
 */
class ExtraFields implements ExtraFieldsInterface {
  use StringTranslationTrait;
  /**
   * Service entity_type.manager.
   *
   * @var Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;
  /**
   * Service entity.form_builder.
   *
   * @var Drupal\Core\Entity\EntityFormBuilderInterface
   */
  protected $formBuilder;
  /**
   * Constructs a new ExtraFields object.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFormBuilderInterface $form_builder) {
    $this->entityTypeManager = $entity_type_manager;
    $this->formBuilder = $form_builder;
  }
  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      // Load the services required to construct this class.
      $container->getParameter('entity_type.manager'),
      $container->getParameter('entity.form_builder')
    );
  }
  /**
   * {@inheritdoc}
   */
  public function entityExtraFieldInfo() {
    $extra = [];
    $extra['paragraph']['contact_form']['display']['contact_form'] = [
      'label' => 'Contact form',
      'description' => 'Render webform contact form. Pseudo_field created on the example_front_id_components_contact module.',
      'weight' => 0,
      'visible' => TRUE,
    ];
    return $extra;
  }
  /**
   * {@inheritdoc}
   */
  public function paragraphView(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
    // Early return if missing component.
    if (!$display->getComponent('contact_form')) {
      return;
    }
    // Get the contact form.
    $form = $this->entityTypeManager->getStorage('webform')->load('contact')->getSubmissionForm();
    $build['contact_form'] = $form;
  }
}

La parte que más me gusta de hacerlo así, es que podemos manipular nuestro objeto embebido dentro del paragraph.

En el ejemplo, las últimas líneas:

    // Get the contact form.
    $form = $this->entityTypeManager->getStorage('webform')->load('contact')->getSubmissionForm();
    // <-- :)
    $build['contact_form'] = $form;
 

tenemos un hueco perfecto para meter parámetros a una vista, cambiar configuración de un formulario o lo que necesitemos en base a campos del paragraph o cualquier otro factor que se nos ocurra (qué usuario está logueado, el nodo que contiene el paragraph, etc.)

Como sé que es mucho código para verlo en un post, aquí teneis un repositorio con el ejemplo:

https://github.com/alvar0hurtad0/example-front-id-paragraph-extrafield

Add new comment

The content of this field is kept private and will not be shown publicly.

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.