Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save adinan-cenci/d35e66e7b1ad9e2bd4ad5ca44e15a663 to your computer and use it in GitHub Desktop.
Save adinan-cenci/d35e66e7b1ad9e2bd4ad5ca44e15a663 to your computer and use it in GitHub Desktop.
Useful Drupal snippets

Comparing differences between entities

/**
 * Compares the current state of an entity with its previous version
 * to check if it has been updated.
 *
 * @param EntityInterface $currentEntity
 *  The entity object.
 *
 * @param EntityInterface|NULL originalEntity $originalEntity
 *   The entity to compare.
 *
 * @return bool
 */
function has_entity_been_updated(EntityInterface $currentEntity, ?EntityInterface $originalEntity = NULL) : bool {
  $original = $originalEntity
    ? $originalEntity->toArray()
    : $currentEntity->original?->toArray() ?? [];
  $current = $currentEntity->toArray();

  recursive_unset($original, ['vid', 'changed', 'target_revision_id', 'revision_timestamp', 'revision_id']);
  recursive_unset($current, ['vid', 'changed', 'target_revision_id', 'revision_timestamp', 'revision_id']);

  $difference = array_diff_assoc_recursive($original, $current);

  return count($difference) > 0;
}

/**
 * Custom function to compute the difference between multi dimensional arrays.
 *
 * @param array $array1
 * @param array $array2
 *
 * @return array
 *   The computed difference between both.
 */
function array_diff_assoc_recursive($array1, $array2) {
  $difference = array();
  foreach ($array1 as $key => $value) {
    if(is_array($value)) {
      if(!isset($array2[$key]) || !is_array($array2[$key])) {
        $difference[$key] = $value;
      }
      else {
        $new_diff = array_diff_assoc_recursive($value, $array2[$key]);
        if (!empty($new_diff)) {
          $difference[$key] = $new_diff;
        }
      }
    }
    else if(!array_key_exists($key,$array2) || $array2[$key] != $value) {
      $difference[$key] = $value;
    }
  }
  return $difference;
}

/**
 * Recusiverly remove keys from a multi-dimensional array.
 */
function recursive_unset(&$array, $unwanted_keys) {
  foreach ($unwanted_keys as $k) {
    unset($array[$k]);
  }
  foreach ($array as &$value) {
    if (is_array($value)) {
      recursive_unset($value, $unwanted_keys);
    }
  }
}

Drush

Need to run the same update hook ( e.g. 8003 ) twice ?

# NOTE: this will cause all module_name_update_N > 8002 to run again.
drush sqlq "UPDATE key_value SET value = 'i:8002;' WHERE name = 'module_name' AND collection = 'system.schema'"

Need to update a configuration ?

# A setting had all inputs on the website forms removed but it is still set in the database ?
drush eval "Drupal::service('config.factory')->getEditable('name_of_the_module.something_something')->set('piece_of_anoyance', ['value' => ''])->save()"

Send email

drush eval "Drupal::service('plugin.manager.mail')->mail('system', 'general_mail', 'adinan@zoocha.com', 'en', ['message' => 'this is a test email message', 'subject' => 'test mail', 'context' => ['message' => 'this is a test email message', 'subject' => 'test mail']], NULL, TRUE)"

## Send email ( Drupal 7 )
drush eval "drupal_mail('system', 'general_mail', 'adinan@zoocha.com', 'en', ['message' => 'this is a test email message', 'subject' => 'test mail', 'context' => ['message' => 'this is a test email message', 'subject' => 'test mail']], NULL)"

Select nodes that have no alias

drush sqlq "SELECT n.nid, DATE_FORMAT(FROM_UNIXTIME(n.changed), '%e %b %Y %H:%i:%s') FROM node_field_data n LEFT JOIN path_alias p ON REPLACE(p.path, '/node/', '') = n.nid LEFT JOIN domain_path d ON REPLACE(d.source, '/node/', '') = n.nid WHERE n.status = 1 AND p.path IS NULL AND d.source IS NULL ORDER BY n.changed DESC"

Manually uninstall module

drush eval "\Drupal::configFactory()->getEditable('core.extension')->clear('module.module_name')->save();"
drush sqlq "DELETE FROM key_value WHERE collection = 'system.schema' AND name IN ('module_name')"

Entities

Load entities

$timestamp = '1640995200'; // 1st of January 2022
$query = \Drupal::entityQuery('commerce_order_item');
$query
  ->accessCheck(FALSE)
  ->condition('created', $timestamp, '>=')
  ->sort('created', 'DESC');

$item_ids = $query->execute();

$order_items = \Drupal::entityTypeManager()
  ->getStorage('commerce_order_item')
  ->loadMultiple($item_ids);

foreach ($order_items as $item) {
  // ... do something ...
}

Desasociate entities

foreach ($entity->field_whatever_reference as $key => $value) {
  if ($value->target_id == $undesirable_id) {
    unset($entity->field_whatever_reference[$key]);
  }
}
$entity->save();

Paragraphs

Load term children

$vid = 'my_vocab_machine_name';
$parent_term_id = 87; // the parent term id
$depth = 1; // 1 to get only immediate children, NULL to load entire tree
$load_entities = FALSE; // True will return loaded entities rather than ids
$child_tids = \Drupal::entityTypeManager()
  ->getStorage('taxonomy_term')
  ->loadTree($vid, $parent_term_id, $depth, $load_entities);

Request

// Get the current route name.
\Drupal::routeMatch()->getRouteName();

// Check if the current route is an admin one.
\Drupal::service('router.admin_context')->isAdminRoute();

// Get a http header
\Drupal::request()->headers->get('header_name');

// Get a $_GET variable.
\Drupal::request()->query->get('variable_name');

// Get a $_POST variable.
\Drupal::request()->request->get('variable_name');

// Get the host name.
\Drupal::request()->getHost();

// get the full url
\Drupal::request()->getSchemeAndHttpHost() . \Drupal::request()->getRequestUri();

Routing

No cache

module.no_cache:
  path: '/whatever'
  defaults:
    _controller: '\Drupal\module\Controller\What:ever'
  options:
    no_cache: TRUE
# Deletes a specific item from a search index.
drush eval "Drupal\search_api\Entity\Index::load('search_content')->trackItemsDeleted('entity:node', ['1499:en'])";
# Indexes it again
drush eval "Drupal\search_api\Entity\Index::load('search_content')->indexSpecificItems(['entity:node/1499:en' => Drupal\node\Entity\Node::load(1499)->getTypedData()])";

Preprocess node

Change date field, but keep date format.

$node = $variables['node'];
$date = something_something_get_date_value_to_override($node->get('field_deadline')->value);

$bundle = $node->getType();
$view_mode = $variables['view_mode'];
$view_mode = $view_mode == 'full'
  ? 'default'
  : $view_mode;

$settings = \Drupal::entityTypeManager()
  ->getStorage('entity_view_display')
  ?->load("node.$bundle.$view_mode")
  ?->getComponent('field_deadline');

$pattern = 'j F Y';
if ($settings && isset($settings['settings']['date_format'])) {
  $pattern = $settings['settings']['date_format'];
}
elseif ($settings && isset($settings['settings']['format_type'])) {
  $format_type = $settings['settings']['format_type'];
  $format = \Drupal::entityTypeManager()->getStorage('date_format')
    ->load($format_type);
  $pattern = $format->getPattern();
}

$variables['content']['field_deadline'][0]['#text'] =
$variables['content']['field_deadline'][0]['#markup'] =
$variables['elements']['field_deadline'][0]['#markup'] = $date->format($pattern);

Preprocess view

/*
 * Implements template_preprocess_views_view().
 * field_event_time is a multi-value field, so the same node can appear 
 * multiple times in the same view. We need to make sure the correct date
 * is displayed.
 */
function my_module_preprocess_views_view(&$variables) {
  $view = $variables['view'];
  if ($view->id() == 'events') {
    $results = $view->result;

    foreach ($variables['rows'][0]['#rows'] as $row_n => &$row) {
      $node = $row['#node'];

      if ($node->get('field_event_time')->count() > 1) {
        $result = $results[$row_n];
        $date_string = $result->node__field_event_time_field_event_time_value_day;
        $date = new Drupal\Component\Datetime\DateTimePlus($date_string);
        $human_format = $date->format('F d, Y');
        $unix_format = $date->format('Y-m-d');
        $row['field_event_time'][0]['start_date'] = [
          '#theme' => 'time',
          '#text' => $human_format,
          '#attributes' => [
            'datetime' => $unix_format
          ]
        ];
        $row['#cache']['max-age'] = 0;
      }
    }
  }
}

Twig

{# For whatever reason this seems to erase other proprieties #}
{{ content.field_link.0|merge({
  '#attributes': { 'target': '_blank' },
}) }}

{# try this #}
{% set link = content.field_box_link.0 %}
{% set href = link['#url'].external ? link['#url'].uri : path(link['#url'].routeName, link['#url'].routeParameters) %}
<a href="{{ href }}" {{ link.attributes|without('target') }} target="_blank">{{ link['#title'] }}</a>

Update

Update hook

// Enable module
function update_module_update_8005() {
  \Drupal::service('module_installer')
    ->install(['some_module','or_another',]);
}

Post update

// Delete bundle ( remember to delete entities first )
function gstt_components_post_update_02_delete_alert_box_paragraph_bundle() {
  $storage = \Drupal::entityTypeManager()->getStorage('paragraphs_type');

  if ($storage) {
    $paragraph_bundle = $storage->load('alert_box');

    if ($paragraph_bundle) {
      $paragraph_bundle->delete();
    }
  }
}

User

// Get the current user
\Drupal\user\Entity\User::load(\Drupal::currentUser()->id());

// Get the current language code
\Drupal::languageManager()->getCurrentLanguage()->getId();

move this to a different file

// get the settings for a webform field inside a presave hook
function module_name_webform_submission_presave($submission) {
  $form = $submission->getWebform();
  $elements = $form->getElementsDecodedAndFlattened();  
  $elements['the_name_of_the_field_here'];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment