Drupal8

Questions related to Drupal 8 with solutions.

How to create a REST Resource and also use dependency injection in it's class

Custom REST Resource can be get used in case you are trying to expose some data from your Drupal website to another external system. In the REST resource code, you might have to access any Drupal services to generate the desired output. Here is a sample code to achieve that.

<?php

namespace Drupal\example\Plugin\rest\resource;

use Drupal\Core\Config\Config;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\node\Entity\Node;
use Drupal\rest\ModifiedResourceResponse;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

/**
 * An example REST resource to expose data from Drupal.
 *
 * @RestResource(
 *   id = "example_resource",
 *   label = @Translation("Example Resource"),
 *   uri_paths = {
 *     "canonical" = "/example-resource-path"
 *   }
 * )
 */
class ExampleRestResource extends ResourceBase {
  
  /**
   * Drupal\Core\Entity\EntityTypeManagerInterface definition.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Drupal configuration instance.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected $apiKeyConfig;
  
  /**
   * A current user instance.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   * Constructs a ExampleResource instance.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param array $serializer_formats
   *   The available serialization formats.
   * @param \Psr\Log\LoggerInterface $logger
   *   A logger instance.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Config\Config $api_key_config
   *   The configuration file.
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   The currently authenticated user.
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    array $serializer_formats,
    LoggerInterface $logger,
    AccountProxyInterface $current_user,
    EntityTypeManagerInterface $entity_type_manager,
    Config $api_key_config
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
    $this->currentUser = $current_user;
    $this->entityTypeManager = $entity_type_manager;
    $this->apiKeyConfig = $api_key_config;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
   return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->getParameter('serializer.formats'),
      $container->get('logger.factory')->get('example'),
      $container->get('current_user'),
      $container->get('entity.manager'),
      $container->get('config.factory')->get('example.settings')
   );
  }


  /**
   * Responds to GET requests.
   *
   *
   * @return \Drupal\rest\ResourceResponse
   *   The HTTP response object.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
   *   Throws exception expected.
   */
  public function get() {
    //Access the entity type manager and config service in this way.
    $this->entityTypeManager;
    $this->apiKeyConfig->get('example_setting_key');
    //Rest of the code to follow.
  }

}
 

How to resolve CSRF token issue in headless/decoupled application ?

Whenever we send a request to Drupal website from our embedded JS application, we have to send a CSRF token with request otherwise it is seen as request forgery issue. You can provide CSRF token to your JS application in the following way:

/**
 * Implements hook_page_attachments().
 */
function example_module_page_attachments(array &$attachments) {
  $attachments['#attached'] = [
    'drupalSettings' => [
      'csrf' => \Drupal::csrfToken()->get(CsrfRequestHeaderAccessCheck::TOKEN_KEY),
    ],
  ];
}

And in your JS application CSRF token can be accessed from drupalSettings object. Make sure this token is added to every request to avoid X-CSRF token not found issues.

How to set Drupal cron using crontab in linux environment?

It is always a nice practice to disable automated cron module and setup Drupal cron tasks from the crontab in linux and use of Drush instead of hitting a request on Drupal generated URL. Here is the way to achieve that:

1. Enter command crontab -e to open the cron tab in editor.

2. Enter the following line and save the file.

    0 */2 * * * cd /var/www/html/example-drupal && /usr/local/bin/drush cron

So this will ensure cron runs every 2 hours. Make sure to set correct Drupal directory and drush path.

How to modify entity form display settings programtically?

Here is an example snippet for the same:

    $settings = \Drupal::entityTypeManager()
      ->getStorage('entity_form_display')
      ->load('commerce_product.default.default')
      ->setComponent('variations', [
        'type' => 'inline_entity_form_complex',
        'weight' => 10,
        'settings' => ['allow_new' => 'true', 'allow_duplicate' => 'true'],
      ])->save();

How to embed Webform in Drupal 8 form?

There might be a situation where a single/multiple webforms have to be added in a custom form or you may want to display webform based on some conditions. Here is an example snippet to achieve the same.

//Load webform programatically.

$webform = \Drupal::entityTypeManager()->getStorage('webform')->load($webform_id);
$webform_markup = $webform->getSubmissionForm();

//Add the markup into a Drupal 8 form.

$form['markup'] = [

      '#prefix' => '<div id = "webform">',
      '#suffix' => '</div>',
      '#type' => 'markup',
      '#markup' => $webform_markup,
      '#weight' => 1,

];

 

How to attach library using hook_preprocess_page?

Hook preprocess can be used to attach libraries on any page in Drupal 8 based on any condition. Developers can also add drupalSettings variable. Here is the code snippet:

/**
 * Hook_preprocess_page().
 */
function example_preprocess_page(&$variables) {

  $variables['#attached']['library'][] = 'example_module/example_library';

  $variables['#attached']['drupalSettings']['siteBaseUrl'] = 'example.com';

}

 

How to set entity form and entity view display settings programatically

Entity form display and Entity view display control which fields are shown in entity creation form and entity display page. Drupal provides complete control of fields and widgets through the user interface. We can also set these settings programmatically by loading correct configuration. 

    $settings = \Drupal::entityTypeManager()
      ->getStorage('entity_form_display')
      ->load('commerce_product.default.default')
      ->removeComponent('body')->save();

So when we run this snippet body field is removed from form display while creating a product of product type default. Feel free to experiment by setting other available configurations in configuration file of type entity view display and entity form display.