Snippets

A collection of small code snippets

Een redirect na login wordt vaak toegevoegd op hook_user_login, maar dat is niet juist. Dit zorgt er voor dat de andere hook_user_login implementaties niet worden uitgevoerd. Het is beter om deze redirect in een custom submit handler te zetten.

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;

/**
 * Implements hook_form_FORM_ID_alter().
 */
function MY_MODULE_form_user_login_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['#submit'][] = 'MY_MODULE_user_login_form_submit';
}

/**
 * Custom submit handler for the login form.
 */ 
function MY_MODULE_user_login_form_submit($form, FormStateInterface $form_state) {
  $url = Url::fromRoute('');
  $form_state->setRedirectUrl($url); 
}

Hoe kun je een node of entity renderen in Drupal 8 zoals met node_view() in Drupal 7 ?
Hoe toon je een node of entity met een display mode?

$nid = 1;
$entity_type = 'node';
$view_mode = 'teaser';
$view_builder = \Drupal::entityTypeManager()->getViewBuilder($entity_type);

// You could also use Node::load($nid);
$storage = \Drupal::entityTypeManager()->getStorage($entity_type);
$node = $storage->load($nid);

$build = $view_builder->view($node, $view_mode);
$output = render($build);

If you want to add a submenu link you first have to load the parent link and then create a submenu link:

use Drupal\menu_link_content\Entity\MenuLinkContent;

function MY_MODULE_update_8001() {
  $menu_link_parents = \Drupal::entityTypeManager()
    ->getStorage('menu_link_content')
    ->loadByProperties([
      'title' => 'Dashboard',
      'menu_name' => 'main',
    ]);

  $menu_link_parent = reset($menu_link_parents);

  if ($menu_link_parent) {
    MenuLinkContent::create([
      'title' => 'Add tasks',
      'link' => ['uri' => 'internal:/add-task'],
      'menu_name' => 'main',
      'weight' => -50,
      'parent' => $menu_link_parent->getPluginId(),
    ])->save();
  }
}

Een view renderen in bijvoorbeeld een formulier is eenvoudig dankzij de buildRenderable() methode, die een render array maakt voor de gegeven view en display:

use Drupal\views\Views;
$view = Views::getView('content');
$form['content'] = $view->buildRenderable('page_1');

Als je de generator metatag wilt verbergen, gebruik dan de hook_page_attachments_alter() hook.

/**
 * Implements hook_page_attachments_alter().
 */
function MY_MODULE_page_attachments_alter(array &$attachments) {
  foreach ($attachments['#attached']['html_head'] as $key => $attachment) {
    if (isset($attachment[1]) && $attachment[1] == 'system_meta_generator') {
      unset($attachments['#attached']['html_head'][$key]);
    }
  }
}

Wil je controleren of de huidige route naar de voorpagina gaat? Daar is een service voor:

if (\Drupal::service('path.matcher')->isFrontPage()) {}

Moet je omleiden naar een specifieke pagina? In Drupal 7 zou je waarschijnlijk drupal_goto() in je callback gebruiken. In Drupal 8 gebruik je RedirectResponse().

// Using procedural PHP.
use Symfony\Component\HttpFoundation\RedirectResponse;

function my_redirect() {
  return new RedirectResponse(\Drupal::url('user.page'));
}

// From a controller
use Drupal\Core\Controller\ControllerBase;

class MyControllerClass extends ControllerBase {

  public function foo() {
    //...
    return $this->redirect('user.page');
  }
}
$form['tagtest'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'taxonomy_term',
  '#title' => 'Taxonomy Term',
];

// With default value
$form['tagtest'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'taxonomy_term',
  '#title' => 'Taxonomy Term',
  '#default_value' => \Drupal\taxonomy\Entity\Term::load(1),
];

// With a selected vocabulary.
$form['tagtest'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'taxonomy_term',
  '#title' => 'Taxonomy Term',
  '#selection_settings' => [
    'target_bundles' => ['tags'],
  ],
];

// Auto create a term if not exist.
$form['tagtest'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'taxonomy_term',
  '#title' => 'Taxonomy Term',
  '#autocreate' => [
    'bundle' => 'tags',  // Required. The bundle name for the new entity.
    'uid' => 1,  // Optional. The user ID for the new entity
  ],
];

In dit codefragment laat ik zien hoe je een class kan toevoegen aan een "more" link in Drupal 8 door template_preprocess_views_view() te gebruiken in je theme THEMENAME.theme bestand:

/**
 * Implements template_preprocess_views_view()
 * @param array $variables
 */
function THEMENAME_preprocess_views_view(&$variables)
{
    $view = $variables['view'];
    if ($view->id() == 'VIEW_ID') {
        $variables['more']['#options']['attributes']['class'][] = 'class_css';
    }
}

// Example how to add a class to more link in specific page or block:

/**
 * @param $variables
 */
function THEMENAME_preprocess_views_view(&$variables)
{
    $view = $variables['view'];
    switch ($view->storage->id()) {
        case 'news':
            if ($view->current_display == 'page_1' || $view->current_display == 'block_1')  {
                $variables['more']['#options']['attributes']['class'] = 'btn btn-primary';
            }
    }
}

Wanneer je een view mode wilt toevoegen aan een custom entity, moet je eerst een view mode toevoegen via een YML configuratie.

Voeg in de module een directory "/config/install" toe. Plaats hier een bestand "core.entity_view_mode.[entity_type_id].[view_mode_naam].yml". (entity_type_id is je entity type, view_mode_name is de machine name van de view mode).

Wanneer de module al actief is en er al entities zijn, kun je dat bestand ook toevoegen aan de config directory en daarna importeren. 

langcode: en
status: false
dependencies:
  module:
    - [entity_type_id]
id: [entity_type_id].[view_mode_name]
label: 'Type your label here'
targetEntityType: [entity_type_id]
cache: true

Soms moet je een veld van een content type aanpassen nadat het al gedefinieerd is en gebruikt wordt.

Als je dat via de admin pagina's doet, krijg je de foutmelding "Er zijn reeds gegevens voor dit veld in de database. De veldinstellingen kunnen niet meer gewijzigd worden.".

Het veld kan niet gewijzigd worden aangezien er al data in zit.

Een manier om het op te lossen is via een hook_update_N implementatie, in mijn geval om een veld van “Text (plain)” naar “Text (formatted, long)” aan te passen.

  $entityType = 'node';
  $fieldName = 'field_text';

  $database = \Drupal::database();
  $table = $entityType . '__' . $fieldName;
  $currentRows = NULL;
  $newFieldsList = [];
  $fieldStorage = FieldStorageConfig::loadByName($entityType, $fieldName);

  if (is_null($fieldStorage)) {
    return;
  }

  // Get all current data from DB.
  if ($database->schema()->tableExists($table)) {
    // The table data to restore after the update is completed.
    $currentRows = $database->select($table, 'n')
      ->fields('n')
      ->execute()
      ->fetchAll();
  }

  // Use existing field config for new field.
  foreach ($fieldStorage->getBundles() as $bundle => $label) {
    $field = FieldConfig::loadByName($entityType, $bundle, $fieldName);
    $newField = $field->toArray();
    $newField['field_type'] = 'text_long';
    $newField['settings'] = [];
    $newFieldsList[] = $newField;
  }

  // Deleting field storage which will also delete bundles(fields).
  $newFieldStorage = $fieldStorage->toArray();
  $newFieldStorage['type'] = 'text_long';
  $newFieldStorage['settings'] = [];

  $fieldStorage->delete();

  // Purge field data now to allow new field and field_storage with same name
  // to be created.
  field_purge_batch(40);

  // Create new field storage.
  $newFieldStorage = FieldStorageConfig::create($newFieldStorage);
  $newFieldStorage->save();

  // Create new fields.
  foreach ($newFieldsList as $nfield) {
    $nfieldConfig = FieldConfig::create($nfield);
    $nfieldConfig->save();
  }

  // Restore existing data in new table.
  if (!is_null($currentRows)) {
    foreach ($currentRows as $row) {
      $database->insert($table)
        ->fields((array) $row)
        ->execute();
    }
  }
$alias = \Drupal\path_alias\Entity\PathAlias::create([
    'path' => '/news',
    'alias' => '/nieuws',
    'langcode' => 'nl',
  ]);
  $alias->save();

Hoe zet je de versie van een module terug naar een specifieke versie (om bijv. updates opnieuw uit te voeren)?

 

# Drupal 7:
drush sqlq "UPDATE system SET schema_version=[schema_version] WHERE name='[module_name]' AND type='module'";

# Drupal 8 / 9
drush ev "drupal_set_installed_schema_version('[module_name]', [schema_version])"