Drupal8

Questions related to Drupal 8 with solutions.

How to make node URL alias mandatory in Drupal 8 and Drupal 9

You can use the following code snippet to change the required attribute of the path field in the node form alter in this way:

/**
 * Implements hook_form_FORMID_alter().
 */
function example_module_form_node_form_alter(&$form, &$form_state) {
  $form['path']['widget'][0]['#open'] = TRUE;
  $form['path']['widget'][0]['alias']['#required'] = TRUE;

}

This will keep the path tab open by default and mark the alias field as required.

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

}