php

Example.php
<?php

declare(strict_types=1);

namespace Drupal\my_module;

use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

class Example {

  public function __construct(
    #[Autowire(service: 'current_user')]
    private readonly AccountInterface $currentUser,
  ) {
  }

  public function getCurrentUser(): AccountInterface {
    return $this->currentUser;
  }

}

my_module.services.yml
services:
  my_module.example:
    class: Drupal\my_module\Service\Example
    autowire: true
  Drupal\my_module\Service\Example: '@my_module.example'

query_manipulate.php
<?php

namespace Drupal\my_module_migrate\Plugin\migrate\source\d8;

use Drupal\migrate\Row;

/**
 * Base class for D8 source plugins to collect field values from Field API.
 *
 *  Available configuration keys:
 *   - id: (optional) The id of the content which should get migrated. This can
 *     be useful to only migrate a selected set of nodes. Excepts multiple ids.
 *
 * @MigrateSource(
 *   id = "my_module_d8_gallery",
 *   source_provider = "my_module_migrate"
 * )
 */
class MyModuleGallery extends ContentEntity {

  /**
   * {@inheritdoc}
   */
  public function query() {
    $query = parent::query();

    if (isset($this->configuration['id'])) {
      $entityDefinition = $this->entityTypeManager->getDefinition($this->configuration['entity_type']);
      $idKey = $entityDefinition->getKey('id');
      $query->condition("d.{$idKey}", $this->configuration['id'], 'IN');
    }

    // Left join to get the nid of the old image node.
    $query->leftJoin('paragraph__field_referenzfeld_galerie', 'pfrg', 'pfrg.entity_id = b.id AND pfrg.revision_id = b.revision_id');
    $query->leftJoin('node__field_gallery_bild', 'nfgb', 'nfgb.entity_id = pfrg.field_referenzfeld_galerie_target_id');

    $query->leftJoin('node__field_base_public_title', 'nfbpt', 'nfbpt.entity_id = pfrg.field_referenzfeld_galerie_target_id');

    $query->addExpression('GROUP_CONCAT(nfgb.field_gallery_bild_target_id)', 'gallery_image_ids');
    // Add public title field.
    $query->addField('nfbpt', 'field_base_public_title_value', 'field_base_public_title_value');

    $query->groupBy('b.id');

    return $query;
  }

  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    $return = parent::prepareRow($row);

    $nids = [];
    $ids_string = $row->getSourceProperty('gallery_image_ids');
    if (!empty($ids_string)) {
      $ids = explode(',', $ids_string);

      foreach ($ids as $id) {
        $nids[] = ['nid' => (int) $id];
      }
      // Add new source property to skip old gallery node within migration.
      $row->setSourceProperty('field_referenzfeld_galerie', $nids);
    }
    $row->setSourceProperty('field_base_public_title', $row->getSourceProperty('field_base_public_title_value'));

    return $return;
  }

}
query.sql
SELECT 
  GROUP_CONCAT(nfgb.field_gallery_bild_target_id), 
  nfbpt.field_base_public_title_value
FROM paragraph__field_referenzfeld_galerie AS pfrg
LEFT JOIN node__field_gallery_bild AS nfgb
  ON nfgb.entity_id = pfrg.field_referenzfeld_galerie_target_id
LEFT JOIN node__field_base_public_title AS nfbpt
  ON nfbpt.entity_id = pfrg.field_referenzfeld_galerie_target_id
WHERE pfrg.entity_id = 100810 AND pfrg.revision_id = 1919384

 

redirect.install
/**
 * Save the bulk delete action to config.
 */
function redirect_update_8104() {
  if (!Action::load('redirect_delete_action')) {
    $entity_type_manager = \Drupal::entityTypeManager();
    $module_handler = \Drupal::moduleHandler();

    // Save the bulk delete action to config.
    $config_install_path = $module_handler->getModule('redirect')->getPath() . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY;
    $storage = new FileStorage($config_install_path);
    $entity_type_manager
      ->getStorage('action')
      ->create($storage->read('system.action.redirect_delete_action'))
      ->trustData()
      ->save();
  }
}
HelloWorldCommands.php
<?php

declare(strict_types=1);

namespace Drupal\nice_module\Drush\Commands;

use Drupal\Component\DependencyInjection\ContainerInterface;
use Drupal\nice_module\HelloWorldService;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands;

/**
 * A Drush command class for saying "hello" to the world.
 */
final class HelloWorldCommands extends DrushCommands {

  public function __construct(
    private readonly HelloWorldService $helloWorldService,
  ) {
    parent::__construct();
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): self {
    return new static($container->get('nice_module.hello_world_service'));
  }

  #[CLI\Command(name: 'nice_module:say-hello', aliases: ['smci'])]
  #[CLI\Argument(name: 'userName', description: 'The name of the user.')]
  public function sayHello(?string $userName = NULL): void {
    $this->helloWorldService->sayHello($userName, $this->output());
    $this->logger()->success('I said "hello" to the user.');
  }

}
nested_array_merge_deep.php
use Drupal\Component\Utility\NestedArray;

// Parent array with default settings.
$parent_array = [
    'config' => [
        'theme' => 'dark',
        'layout' => [
            'width' => 800,
            'height' => 600,
        ],
    ],
];

// Child array adds more nested data but doesn't override existing values.
$child_array = [
    'config' => [
        'layout' => [
            'depth' => 300, // New nested key
        ],
        'features' => [
            'animations' => true, // New section
        ],
    ],
];

// Merge both arrays.
$merged_array = NestedArray::mergeDeep($parent_array, $child_array);
nested_array_result.php
[
    'config' => [
        // Unchanged (not overridden)
        'theme' => 'dark', 
        'layout' => [
            // Keeps parent value
            'width' => 800, 
            // Keeps parent value  
            'height' => 600,
            // New nested key added
            'depth' => 300,   
        ],
        'features' => [
            // New section added
            'animations' => true, 
        ],
    ],
]
30.07.2026 | Lothar Ferreira Neumann

Merge multidimensional arrays in Drupal

cleanup_aliases.php
<?php

/** @var \Drupal\path_alias\PathAliasStorage */
$alias_storage = \Drupal::entityTypeManager()->getStorage('path_alias');
$db = \Drupal::database();

$langcodes = array_keys(\Drupal::languageManager()->getLanguages());

$total = 0;
$duplicates = "";

// Get a list of all distinct aliases.
$query = $db->select('path_alias', 'pa')
  ->fields('pa', ['alias'])
  ->orderBy('alias')
  ->distinct();
$all_aliases = $query->execute()->fetchAll(\Pdo::FETCH_COLUMN);

foreach ($all_aliases as $alias) {
  // Some aliases are 'NULL'.
  if (!$alias) {
    continue;
  }

  // We only look for duplicates within the langcode.
  foreach ($langcodes as $langcode) {
    // (1) Get the newest ID for that alias and langcode.
    $query = $db->select('path_alias', 'pa')
      ->fields('pa', ['id'])
      ->condition('alias', $alias)
      ->condition('langcode', $langcode)
      ->orderBy('id', 'DESC')
      ->range(0, 1);
    $newest_id = $query->execute()->fetchField(0);
    if (!$newest_id) {
      // There is no alias for that langcode.
      // So there are also no duplicates.
      continue;
    }

    // (2) Select all ids lower than it with the same alias and langcode.
    $query = $db->select('path_alias', 'pa')
      ->fields('pa', ['id'])
      ->condition('alias', $alias)
      ->condition('langcode', $langcode)
      ->condition('id', $newest_id, '<');
    $duplicate_ids = $query->execute()->fetchAll(\PDO::FETCH_COLUMN);

    if (!str_starts_with($alias, "/")) {
        $query = $db->select('path_alias', 'pa')
        ->fields('pa', ['id'])
        ->condition('alias', "/" . $alias)
        ->condition('langcode', $langcode);
        $ids_with_slash = $query->execute()->fetchAll(\PDO::FETCH_COLUMN);
        if (count($ids_with_slash) > 0) {
            // We can safely delete the one without.
            $to_delete = $alias_storage->loadByProperties([
                'alias' => $alias,
                'langcode' => $langcode,
            ]);
            $alias_storage->delete($to_delete);
        } else {
            // It's the only one? Update with slash.
            $alias_entitys = $alias_storage->loadByProperties([
                'alias' => $alias,
                'langcode' => $langcode,
            ]);
            if (!empty($alias_entitys)) {
                $alias_entity = reset($alias_entitys);
                $alias_entity->set('alias', '/' . $alias);
                $alias_entity->save();
            }
        }
    }

    // We delete those with the alias storage since we want Drupal to handle it
    // and it will delete revisions as well.
    $duplicate_aliases = $alias_storage->loadMultiple($duplicate_ids);
    $total += count($duplicate_aliases);
    if (count($duplicate_aliases) > 0) {
        $duplicates = $duplicates . $alias . PHP_EOL;
    }
    $alias_storage->delete($duplicate_aliases);
  }
}

echo(sprintf("Deleting %d duplicate aliases..." . PHP_EOL, $total));
echo($duplicates);
echo("DONE" . PHP_EOL);
21.02.2025 | Nikolas Kopp

Clean up migrated path aliases

If this does not work...

broken_fapi_autocomplete.php
$form['nodes'] = [
    '#title' => $this->t('Select articles'),
    '#type' => 'entity_autocomplete',
    '#target_type' => 'node',
    '#tags' => TRUE,
    '#selection_handler' => 'default',
    '#selection_settings' => ['target_bundles' => ['article']],
    '#default_value' => $default_nodes,
];

...try adding an increased maxlength value:

fixed_fapi_autocomplete.php
$form['nodes'] = [
    '#title' => $this->t('Select articles'),
    '#type' => 'entity_autocomplete',
    '#target_type' => 'node',
    '#maxlength' => 1024,
    '#tags' => TRUE,
    '#selection_handler' => 'default',
    '#selection_settings' => ['target_bundles' => ['article']],
    '#default_value' => $default_nodes,
];
static_or_nonstatic_that_is_the_question.php
// Static way.      
$slot_paragraph = Paragraph::create([
    'type' => 'slot',
]);
$slot_paragraph->save();

// Nonstatic way.      
$entity_type_manager = \Drupal::entityTypeManager();
$storage = $entity_type_manager->getStorage('paragraphs');
$slot_paragraph = $storage->create([
    'type' => 'slot',
]);
$slot_paragraph->save();
entity_key_id.php
$entity_type_id = 'node';
$definition = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
$id_key = $definition->getKey('id');
10.09.2026 | Mathias Grab

Get "key" from entity type

null_return.php
/**
 * Retrieves the name of a role based on its ID.
 *
 * @param string $role_id
 *   The ID of the role to retrieve.
 *
 * @return string|null
 *   The name of the role if it exists, or NULL if the role is not found.
 */
public function getRoleName(string $role_id): ?string {
  // Example roles array.
  $roles = [
    'admin' => 'Administrator',
    'editor' => 'Content Editor',
    'viewer' => 'Viewer',
  ];

  // Use the null coalescing operator to return the role name or null.
  return $roles[$role_id] ?? NULL;
}