drupal8snip

كتابات: 












IMPORTANT NOTE: These snippets is a direct snippets. Please make sure to use dependency injection always to make sure to follow the standards and to make your code testable later on.
// Execute command in all subfolders.
for d in ./*/ ; do (cd "$d" && touch hi.txt); done

for i in {1..33}; do (lando drush dcer taxonomy_term $i --folder=modules/custom/ddd_default_content/content); done

// Execute command in a specific subfolders.
for d in "folder1" "folder2"; do (cd "$d" && touch hi-d.txt); done

// Execute using a function.
testfunction1() { cd "$1" && touch "$2" && cd .. }
testfunction1 foldername filename.txt

// Registry rebuild. If you just moved module folder and you need Drupal to read the new one.
drush ev "drupal_flush_all_caches();"
drush cr

// Lando docker network issues, happen sometimes after update:
docker network prune
// 20220623
// Extend Drupal class and respecting the Backward compatibility.

We should obey the Backward Compatibility when we extend Drupal classes. We may need to think if Drupal class injected a new service and our class has overrides the constructor function.

Please read this resource: https://www.previousnext.com.au/blog/safely-extending-drupal-8-plugin-classes-without-fear-of-constructor-changes

And review `Search API` contrib module implementation of that:
- Class `IndexClearConfirmForm` : [link](https://git.drupalcode.org/project/search_api/-/blob/1c48ee20c78e9d1091db24b449b7987994c450b7/src/Form/IndexClearConfirmForm.php#L23)
- Class `IndexController` : [link](https://git.drupalcode.org/project/search_api/-/blob/6914422ea083ec41b5c471f74808d5d17ca9515b/src/Controller/IndexController.php#L43)

// Things we do regularly.
// 1. Hide the draggable table rows. ?


// 1. Restrict access to revision information from node form.
      if (isset($form['revision_information'])) {
        $form['revision_information']['#access'] = FALSE;
      }
      if (isset($form['revision_log'])) {
        $form['revision_log']['#access'] = FALSE;
      }
      if (isset($form['revision'])) {
        $form['revision']['#access'] = FALSE;
      }
// 20190110
// Drupal 8 generate uuid.
$uuid = \Drupal::service('uuid')->generate();

// Drupal form clean values array.
$values = $form_state->cleanValues()->getValues('');

// Getting node author uid.
$node->getOwnerId();

// Checks whether a string appears to be in the format of a UUID.
use Drupal\Component\Uuid\Uuid;
Uuid::isValid($uuid_to_validate);

// Install new drupal 8 necessary contrib modules.
composer require drupal/admin_toolbar drupal/adminimal_theme drupal/rename_admin_paths

// Published constant value.
NodeInterface::PUBLISHED
NodeInterface::PROMOTED
NodeInterface::STICKY
NodeInterface::NOT_PUBLISHED
NodeInterface::NOT_PROMOTED
NodeInterface::NOT_STICKY

// Install Drupal console.
composer require drupal/console --optimize-autoloader
// Views hook orders:
// Source: https://www.drupal.org/project/views/issues/1329438#comment-13020162
views_plugins
views_data
views_data_alter
views_plugins_alter
views_default_views_alter
views_pre_view
views_pre_build
views_query_alter
views_query_substitutions
views_post_build
views_pre_execute
views_post_execute
views_pre_render
views_post_render
// Views hooks preprocess execution order.
// Source: https://drupal.stackexchange.com/a/180714/24113
hook_preprocess_views_view
hook_preprocess_views_view_field
hook_preprocess_views_view_fields
hook_preprocess_views_view_grid
hook_preprocess_views_view_table
hook_preprocess_views_view_unformatted
hook_preprocess_views_view_list
// howto change your drupal HTML markup to not be like the default Drupal website.
// Add this line to your settings.php file. (MAKE SURE YOU ARE DOING THIS NOT ON A LIVE WEBSITE)
// This line will change /sites/default/files folder and make it /uploads.
$settings['file_public_path'] = 'uploads';

// You may want to remove Generator meta tag.
https://drupal.stackexchange.com/a/226781
// drupal 8 load term by custom field
$term = current(\Drupal::entityTypeManager()->getStorage('taxonomy_term')
  ->loadByProperties(['field_CUSTOM_NAME' => 'THE_VALUE', 'vid' => 'VOCABULARY_MACHINE_NAME'])
);

// Load term by tid. Load taxonomy term.
$term = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($tid);
// Drupal 8 fetch taxonomy term custom field from term object.
print $term->get('field_CUSTOM_NAME')->getValue()[0]['value'];
print $term->get('tid')->getValue()[0]['value'];
print $term->get('vid')->getValue()[0]['target_id'];
print term->get('name')->getValue()[0]['value'];
// Taxonomy term save multiple values.
$VALUES = $term->get('field_CUSTOM_NAME')->getValue();
$VALUES[]['value'] = 'NEW VALUE';
$term->field_CUSTOM_NAME->setValue($VALUES);
// Drupal 8 save and get load cookie.
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Cookie;
$SymfonyResponse = new Response();
$cookie = new Cookie('YOUR_COOKIE_KEY', 'VALUE_HERE_PLEASE', 0, '/' , NULL, FALSE);
$SymfonyResponse->headers->setCookie($cookie);
$SymfonyResponse->send();

// Load cookie.
$request_cookie = \Drupal::request()->cookies->all();
print $request_cookie['YOUR_COOKIE_KEY'];
// Drupal 8 get user IP.
$current_ip = \Drupal::request()->getClientIp();
// Drupal8 save node programmatically.
$node = Node::create([
  'type'        => 'article',
  'title'       => 'TITLE_HERE',
  'field_category' => [
    'target_id' => 'TID'
  ],
]);
$node->save();
// 20190115
// Drupal 8 read request headers for current user request and get header values.
use Symfony\Component\HttpFoundation\ServerBag;
$headers = new ServerBag($_SERVER);
$headers = $headers->getHeaders();
print_r($headers);
  // Drupal 8 load nodes by custom Taxonomy field.
  $nodes = \Drupal::entityTypeManager()
    ->getStorage('node')
    ->loadByProperties(['type' => 'CONTENT_TYPE', 'field_CUSTOM_TERM_REF_FIELD' => $tid]);
// Drupal8 load all nodes from a specific content type.
$nids = \Drupal::entityQuery('node')->condition('type','CONTENT_TYPE')->execute();
$nodes =  \Drupal\node\Entity\Node::loadMultiple($nids);
// 20190308 Bali
// Loading current user details.
$user = User::load(\Drupal::currentUser()->id());
// 20190308
// Getting and load nodes related to a specific user using entityQuery.
  $query = \Drupal::entityQuery('node')
    ->condition('status', 1) //published or not
    ->condition('type', 'CONTENT_TYPE') //content type
    ->condition('uid', \Drupal::currentUser()->id()) //content type
    ->pager(10); //specify results to return
  $nids = $query->execute();

  // Using entityTypeManager.
  $nodes = \Drupal::entityTypeManager()
    ->getStorage('node')
    ->loadByProperties(['type' => 'CONTENT_TYPE', 'uid' => \Drupal::currentUser()->id()]);
// 20190308
// Load file URL from file field value.
  $fid = $entity->get('field_IMAGE')->getValue()[0]['target_id'];
  $file = \Drupal\file\Entity\File::load($fid);
  $image_url = $file->url();
  // $image_url = file_create_url($file->getFileUri());

// Getting styled URL from drupal 8 custom image field.
  $fid = $entity->get('field_IMAGE')->getValue()[0]['target_id'];
  $file = \Drupal\file\Entity\File::load($fid);
  $image_uri = $file->getFileUri();
  $styled_url = ImageStyle::load('large')->buildUrl($image_uri);
// 20190617
// Page cache can not be controlled by max-age or contexts for anyonymous. You can prevent that kind of caching by using this method to avoid caching for the page or prevent caching in forms.
// Source: https://drupal.stackexchange.com/a/219583/24113
\Drupal::service('page_cache_kill_switch')->trigger();
// 20190619
// Save user programmatically.
    $language = \Drupal::languageManager()->getCurrentLanguage()->getId();
    $new_user = User::create();
    // Mandatory.
    $new_user->setPassword('PASSWORD_AS_TEXT');
    $new_user->enforceIsNew();
    $new_user->setEmail('[email protected]');
    $new_user->setUsername('USER_NAME');
    // Optional.
    $new_user->set('init', '[email protected]');
    $new_user->set('langcode', $language);
    $new_user->set('preferred_langcode', $language);
    $new_user->set('preferred_admin_langcode', $language);
    $new_user->addRole('ROLE_NAME');
    // Set out custom values.
    $new_user->set('field_CUSTOM', 'VALUE');
    $new_user->activate();

    _user_mail_notify('register_no_approval_required', $new_user);
    user_login_finalize($new_user);
    \Drupal::messenger()->addStatus($this->t('Registration successful. You are now logged in.'));
    $form_state->setRedirect('');
// 20190619
// Load user by specific custom field.
$id_number_check = \Drupal::entityQuery('user')
      ->condition('status', 1)
      // ->condition('roles', 'ROLE_NAME')
      // ->condition('roles',['ROLE_NAME_1', 'ROLE_NAME_2'], 'IN')
      // ->condition('status', 1)
      // ->sort('uid', 'ASC')
      // ->range(0, 1)
      ->condition('field_NAME', 'VALUE')
      ->execute();
// 20190626
// Save taxonomy programmatically.
  use Drupal\taxonomy\Entity\Term;
  $term = Term::create([
    'name' => 'test',
    'vid' => 'client',
  ]);
  $term->save();
  print $term->id();
// 20190702
// Since `format_date` is deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.

    // using Drupal time service.
    $time_value = \Drupal::time()->getCurrentTime();
    print \Drupal::service('date.formatter')->format($time_value, 'long');

    // Using DrupalDateTime class.
    use Drupal\Core\Datetime\DrupalDateTime;

    // Getting site default timezone value.
    $timezone = Drupal::config('system.date')->get('timezone')['default'];
    // User default timezone is: drupal_get_user_timezone().
    // Instead of time() use this next line.
    $time_value = \Drupal::time()->getCurrentTime();
    $date_original = DrupalDateTime::createFromTimestamp($time_value, $timezone);
    print $date_original->getTimestamp();
    print $date_original->format('Y-m-d\TH:i:s');

// Drupal 8 strtotime
$timezone = Drupal::config('system.date')->get('timezone')['default'];
$time_value = \Drupal::time()->getCurrentTime();
$date_original = DrupalDateTime::createFromTimestamp($time_value, $timezone);
print strtotime('+1 day', $date_original->getTimestamp());
// 20190703
// Generate URL as HTML in Drupal 8
// Always it's better to use fromRoute() instead of fromUri() to make sure to include the language prefix in the URL.
$register_link_from_uri = render(Link::fromTextAndUrl('Register', Url::fromUri('base:user/register', ['attributes' => ['class' => 'extra-link-register']]))->toRenderable());
$register_link_from_route = render(Link::fromTextAndUrl('Register', Url::fromRoute('user.register', [], ['attributes' => ['class' => ['extra-link-register']]]))->toRenderable());
$password_link_from_route = render(Link::fromTextAndUrl(t('Reset your password'), Url::fromRoute('user.pass', [], ['attributes' => ['class' => ['extra-link-reset-password']]]))->toRenderable());
print $password_link_from_route; // Will print HTML code of rendered link.

// External URL as string.
$url = Url::fromUri('https://www.example.com/');
$link = Link::fromTextAndUrl('URL_TEXT_HERE', $url);
print $link->toString();

// Form redirect to a view route.
    $url = Url::fromRoute('view.VIEW_MACHINE_NAME.DISPLAY_MACHINE_NAME', [
      'node' => $node->id(),
    ]);
    $form_state->setRedirectUrl($url);

// New request link going to node 1 view page :)
$add_new = render(Link::fromTextAndUrl(t('New request'), Url::fromRoute('entity.node.canonical', ['node' => 1], [
  'attributes' => [
    'class' => [
      'button',
      'button--primary',
    ],
  ],
]))->toRenderable());
// 20190715
// Getting content moderation state value.
$moderation_state = $node->get('moderation_state')->getValue();
$moderation_state = $moderation_state[0]['value'];
// 20190715
// Redirect to a specific route.
    $url = Url::fromRoute('view.VIEW_MACHINE_NAME.DISPLAY_MACHINE_NAME', [
      'node' => $node->id(),
    ])->toString();
    $response = new RedirectResponse($url);
    $response->send();

// Getting the URL as plain text full URL
    $url = Url::fromRoute('view.VIEW_MACHINE_NAME.DISPLAY_MACHINE_NAME', [
      'node' => $node->id(),
    ], ['absolute' => TRUE])->toString();
// 20190715
// Load all referenced entities from a multi valued field.
// For example this is a reference field to taxonomy terms.
// https://gorannikolovski.com/blog/how-loop-through-referenced-entities
$node->get('field_NAME')->referencedEntities();
// 20190715
// Alter view fields output.
/**
 * Implements hook_views_pre_render().
 */
function HOOK_views_pre_render(ViewExecutable $view) {
  if (($view->id() == 'VIEW_NAME') && ($view->current_display == 'DISPLAY_NAME')) {
    foreach ($view->result as $key => &$row) {
      print_r(json_decode(json_encode($row)));
      print $row->_entity->id();
      // Fetch the entities from the relationship.
      foreach ($row->_relationship_entities as $entity) {
        print $entity->id();
      }

      // Exit to view field keys extracted from $row.
      exit;
      // Alter view field.
      $row->node_field_data_title = 'TEST TITLE VALUE';
    }
  }
}
// 20190715
// Drupal 8 alter nothing field in views. Alter views fields before output.
/**
 * Implements template_preprocess_views_view_fields().
 */
function MODULENAME_preprocess_views_view_field(&$vars) {
  // Print all available fields.
  foreach ($vars['view']->field as $key => $field) {
    // We will print the field name.
    print $key . '<HR>';
  }
  exit;

  // To access current row entity.
  $entity = $vars['row']->_entity;
  $entity_id = $entity->id();

  // To access entities from relationship.
  $entities = $vars['row']->_relationship_entities;

  // When you find your field key use this code below.
  if(isset($vars['view']) && ($vars['view']->id() == 'VIEW_MACHINE_NAME') && ($vars['view']->current_display == 'DISPLAY_MACHINE_NAME')) {
    if (isset($vars['view']->field) && (count($vars['view']->field) > 0)) {
      // if ($vars['field']->field == 'YOUR_FIELD_NAME')
      if ($vars['field']->field == 'nothing') {
        $vars['output'] = 'TEST_CUSTOM_VALUE';
      }
    }
  }
}
// 20190717
// Render image as HTML. Render img as HTML output.
$file_id = '1111';
$image_file = \Drupal\file\Entity\File::load($file_id);
$image_uri = $image_file->getFileUri();
$build = [
  '#theme' => 'image_style',
  '#style_name' => 'thumbnail',
  '#uri' => $image_uri,
];
/** @var \Drupal\Core\Render\Renderer $renderer */
$renderer = \Drupal::service('renderer');
$img_html = $renderer->render($build);
print $img_html;
// Drupal 8 Remove title from the node view. Remove any field from a specific rendered node view mode.
// You can also override the display options by using getComponent() and setComponent() from EntityDisplayBase class.
/**
 * Implements hook_entity_view_display_alter().
 */
function MODULENAME_entity_view_display_alter(\Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, array $context) {
  if (isset($context['entity_type']) && ($context['entity_type'] == 'node')
  && isset($context['bundle']) && ($context['bundle'] == 'CONTENT_TYPE')
  && isset($context['view_mode']) && ($context['view_mode'] == 'VIEW_MODE')) { // teaser, full ..
    $display->removeComponent('title');
    $display->removeComponent('field_NAME');

    // Still, I'm trying to remove only the title link :)
    // keywords: drupal 8 remove link from title field display link_to_entity.
  }
}
// 20190718
// Load paragraph entity from node object.
if ($node->field_PARAGRAPH_FIELD) {
  foreach ($node->field_PARAGRAPH_FIELD as $item) {
    $paragraph = Paragraph::load($item->target_id);
  }
}
// Force using specific form view mode.
/**
 * Implements hook_entity_type_alter().
 */
function MODULENAME_entity_form_display_alter(&$form_display, $context) {
  // Check the specific content type that we are targeting.
  if (isset($context['entity_type']) && isset($context['bundle'])
    && ($context['entity_type'] == 'node') && ($context['bundle'] == 'CONTENT_TYPE_MACHINE_NAME')) {
    // Get the current user.
    $user = \Drupal::currentUser();
    // Force our custom view mode if the current user is not having this permission.
    if (!$user->hasPermission('CUSTOM PERMISSION')) {
      $storage = \Drupal::service('entity_type.manager')->getStorage('entity_form_display');
      $form_display = $storage->load('node.CONTENT_TYPE_MACHINE_NAME.VIEW_MODE_MACHINE_NAME');
    }
  }

  // Force using a specific view mode in user form if user does not have a specific permission.
  if (isset($context['entity_type']) && isset($context['bundle'])
    && ($context['entity_type'] == 'user') && ($context['bundle'] == 'user')) {
    // Get the current user.
    $user = \Drupal::currentUser();
    // Force our custom view mode if the current user is not developer.
    if (!$user->hasPermission('CUSTOM PERMISSION')) {
      $storage = \Drupal::service('entity_type.manager')->getStorage('entity_form_display');
      $form_display = $storage->load('user.user.VIEW_MODE_MACHINE_NAME');
    }
  }
}
// 20190721
// Force a specific view mode on entity display page.
/**
 * Implements hook_entity_view_mode_alter().
 */
function MODULENAME_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInterface $entity, $context) {
  // Check the specific entity type that we are targeting.
  if (($entity->getEntityTypeId() == 'user') && ($entity->bundle() == 'user') && ($view_mode == 'full')) {
    // Get the current user.
    $user = \Drupal::currentUser();
    // Force our custom view mode if the current user does not have a specific permission.
    if (!$user->hasPermission('PERMISSION NAME')) {
      // Make sure to enable the (compact) view mode of the user from /admin/config/people/accounts/display
      $view_mode = 'compact';
    }
  }

  // Same code but for specific content type.
  if (($entity->getEntityTypeId() == 'node') && ($entity->bundle() == 'CONTENT_TYPE_MACHINE_NAME') && ($view_mode == 'full')) {
  }
}
// drupal 8 alter view mode field value.
// Create a virtual field when display an entity.
/**
 * Implements hook_entity_view_alter().
 */
function MODULENAME_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
  if (($display->getTargetEntityTypeId() == 'node') && ($display->getTargetBundle() == 'CONTENT_TYPE_MACHINE_NAME') && ($display->getOriginalMode() == 'VIEW_MODE')) {
    $build['field_virtual'] = [
      '#markup' => 'HEEEY!',
      '#weight' => 99,
    ];
  }
  // Check if this is our targeted view.
  if (($display->getOriginalId() == 'user.user.full') && ($display->getEntityTypeId() == 'entity_view_display')) {
    print $display->getOriginalId();
    print '<HR>';
    print $display->getTargetEntityTypeId();
    print '<HR>';
    print $display->getOriginalMode();
    print '<HR>';
    print $display->getEntityTypeId();
    print '<HR>';
    print $display->getTargetBundle();
    exit;
  }
}
// 20190728
// Update node and save it as a new revision.
$node->set('field_test', $value);
// Making sure to save this update as a new revision.
$node->setNewRevision(TRUE);
$node->revision_log = 'write_log_message_here';
$node->setRevisionCreationTime(REQUEST_TIME);
$node->setRevisionUserId(\Drupal::currentUser()->id());
$node->save();
// 20190730
// drupal 8 template_preprocess_views_view alter row markup.

// 20190731
// Tempstore.
// Source: http://karimboudjema.com/en/drupal/20190315/saving-temporary-values-form-private-tempstore-drupal-8
tempstore.private
// 1. Get the private tempstore factory, inject this in your form, controller or service.
$tempstore = \Drupal::service('tempstore.private');
// Get the store collection. 
$store = $tempstore->get('my_module_collection');
// Set the key/value pair.
$store->set('key_name', $value);

// 2. Get the value somewhere else in the app.
$tempstore = \Drupal::service('tempstore.private');
// Get the store collection. 
$store = $tempstore->get('my_module_collection');
// Get the key/value pair.
$value = $store->get('key_name');

// Delete the entry. Not mandatory since the data will be removed after a week.
$store->delete('key_name');

// --
// Deprecated services
$tempstore = \Drupal::service('user.private_tempstore')->get('my_module_name');
$tempstore = \Drupal::service('tempstore.shared')->get('my_module_name');
// Source: https://www.drupal.org/node/2935639
// 20190820
// Load field info .. load field settings ... field config info
// Get paragraph field type (file) file_extensions from field instance.
$field_instance = \Drupal::entityTypeManager()->getStorage('field_config')->load('paragraph.PARAGRAPH_TYPE_NAME.field_NAME');
$settings = $field_instance->getSettings();
print $settings['file_extensions'];

$field_instance = \Drupal::entityTypeManager()->getStorage('field_config')->load('node.CONTENT_TYPE.field_NAME');
$field_instance = \Drupal::entityTypeManager()->getStorage('field_config')->load('user.user.field_NAME');
// 20190829
// Auto import languages.
// Add these two lines to your module .info file.
'interface translation project': MODULE_NAME
'interface translation server pattern': modules/custom/MODULE_NAME/translations/%project-%language.po
// The .po file should be exists inside your module.
// Don't miss to configure your Import behavior on:  /admin/config/regional/translate/settings
// Import from UI: /admin/reports/translations
// Drush command:
// drush locale-check && drush locale-update && drush cr
// @NOTE: It is not a good idea to do this if you are working on your contrib module since the translation files should be on a separate folder. (Thanks mhmd Gomma)
// For more info please review these two lines:
https://git.drupalcode.org/project/drupal/blob/8.8.x/core/modules/locale/locale.api.php#L30
https://git.drupalcode.org/project/drupal/blob/8.8.x/core/modules/locale/locale.api.php#L55
// 20190829
// Get site name $site_name
$site_name = Drupal::config('system.site')->get('name');
print $site_name;
// 20190924
// Delete field programmatically.
use Drupal\field\Entity\FieldStorageConfig;
$field = FieldStorageConfig::loadByName('taxonomy_term', 'field_tr_title');
if ($field) {
  // Delete this field.
  $field->delete();
}
else {
  // The field can not be loaded or maybe it does not exist.
}
// 20191010
// Invalidate cached rendered context.
Cache::invalidateTags(['rendered']);
// 20191222
// Getting private file URL as a string.
$fid = 1;
$file = File::load($fid);
$file_uri = $file->getFileUri();
$file_name = $file->getFilename();
$stream = \Drupal::service('stream_wrapper_manager')->getViaUri($file_uri);
$file_url = $stream->getExternalUrl();
// 20200318
// Drupal entityQuery Query isNull. how to check if query field value is null.
// is to use ->notExists(). This will get the NULL values for you. Even if the value was saved before then was emptied after that.
    $nodes = \Drupal::entityQuery('node')
      ->condition('type', 'CONTENT_TYPE_NAME')
      ->condition('field_CUSTOM_ONE', 'VALUE')
      ->notExists('field_CUSTOM_TWO')
      ->execute();
    if (is_array($nodes) && (count($nodes) > 0)) {
      print_r($nodes);exit;
      foreach ($nodes as $nid) {
        $node = Node::load($nid);
      }
    }
// 20201218
// Getting base URL
$host = \Drupal::request()->getHost();
$host = \Drupal::request()->getSchemeAndHttpHost();
// Source: https://drupal.stackexchange.com/a/202811/24113
// Loading field settings.
    // $field_definition = FieldConfig::loadByName($entity_type, $bundle, $field_name);
    $field_definition = FieldConfig::loadByName('paragraph', 'PARAGRAPH_MACHINE_NAME', 'FIELD_CUSTOM');
    $field_allowed_values_array = $field_definition->getSettings()['allowed_values'];

// Check if user has specific access. user access user_access()
// Source: https://www.drupal.org/node/2049309
\Drupal::currentUser()->hasPermission('name of permission');

// OR
$account = \Drupal\user\Entity\User::load(3);
$account->hasPermission('name of permission');
// 20211025
// Get all blocks IDs. Get block id value
print_r(array_keys(\Drupal::service('plugin.manager.block')->getDefinitions()));
// 20220105
// settings.local.php for development environment
$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml';
$settings['cache']['bins']['render'] = 'cache.backend.null';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';
$settings['cache']['bins']['page'] = 'cache.backend.null';
$settings['extension_discovery_scan_tests'] = FALSE;
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;
$config['system.logging']['error_level'] = 'verbose';

# development.services.yml
parameters:
  twig.config:
    debug: true 

# FULL
parameters:
    session.storage.options: { gc_probability: 1, gc_divisor: 100, gc_maxlifetime: 200000, cookie_lifetime: 2000000 }
    twig.config: { debug: true, auto_reload: true, cache: false }
    renderer.config: { required_cache_contexts: ['languages:language_interface', theme, user.permissions], auto_placeholder_conditions: { max-age: 0, contexts: [session, user], tags: {  } } }
    http.response.debug_cacheability_headers: true
    factory.keyvalue: {  }
    factory.keyvalue.expirable: {  }
    filter_protocols: [http, https, ftp, news, nntp, tel, telnet, mailto, irc, ssh, sftp, webcal, rtsp]
    cors.config: { enabled: false, allowedHeaders: {  }, allowedMethods: {  }, allowedOrigins: ['*'], exposedHeaders: false, maxAge: false, supportsCredentials: false }
services:
  cache.backend.null:
    class: Drupal\Core\Cache\NullBackendFactory


# 9.1
  renderer.config:
    required_cache_contexts: ['languages:language_interface', 'theme', 'user.permissions']
    auto_placeholder_conditions:
      max-age: 0
      contexts: ['session', 'user']
      tags: []
    debug: true
// 20220108
// Render view programmatically.
$view = \Drupal\views\Views::getView('VIEW_NAME');
$view->setDisplay('DISPLAY_NAME');
$view->setArguments([]);
$view->execute();
$result = $view->buildRenderable('DISPLAY_NAME', []);
$result = render($result);
// 20220108
// Set view filter programmatically.
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\query\QueryPluginBase;
/**
 * Implements hook_views_query_alter().
 */
function HOOK_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  if (($view->id() == 'VIEW_NAME') && ($view->current_display == 'DISPLAY_NAME')) {
    foreach ($query->where as &$condition_group) {
      foreach ($condition_group['conditions'] as &$condition) {
        // Ignore some conditions.
        if (in_array($condition['field'], ['node_field_data.status', 'node_field_data.type'])) {
          continue;
        }

        if ($condition['field'] == 'taxonomy_term_field_data_taxonomy_term__parent_1.tid') {
          $condition = [
            'field' => 'taxonomy_term_field_data_taxonomy_term__parent_1.tid',
            'value' => (1, 2, 3),
            'operator' => 'IN',
          ];
        }
      }
    }
  }
}
// 20220108
// TWIG TRIM
{{ data.description.plain|truncate(8, true, true) }}
// TWIG class name
{{ data.machine_name|clean_class }}

{% if not logged_in  %}
  {% include '@THEMENAME/page--anonymous.html.twig' %}
{% else %}
  {% include '@THEMENAME/page--authenticated.html.twig' %}
{% endif %}
// 20220124
// Twig absolute URL
{{ drupal_url(active_theme_path() ~ '/images/avatar.png', {absolute: true}) }}
{{ drupal_url('/login', {absolute: true}) }}
{{ drupal_url('/list/' ~ data.id ~ '/' ~ data.machine_name ~ '/all', {absolute: true}) }}
{{ drupal_url(path('ROUTE.NAME_HERE', {'PARAM1': data.value, 'PARAM2': data.id}), {absolute: true}) }}
// 20220124
// menu.html.twig
{% import _self as menus %}
{{ menus.menu_links(items, attributes, 0, menu_name) }}
{% macro menu_links(items, attributes, menu_level, menu_name) %}
  {% import _self as menus %}
  {% if items %}
    {% if menu_level == 0 %}
  
  {% else %}
  
    {% endif %} {% for item in items %} {% set classes_link = [ 'nav-link', item.is_expanded ? 'dropdown-toggle', item.is_collapsed ? 'dropdown-toggle', item.in_active_trail ? 'active', ] %} {{ link(item.title, item.url, { 'class': classes_link }) }} {% if item.below %} {{ menus.menu_links(item.below, attributes, menu_level + 1) }} {% endif %} {% endfor %}
{% endif %} {% endmacro %}
// Check if file private or public.
$stream_wrapper = \Drupal::service('file_system')->uriScheme($file_object->getFileUri())

D9: $stream_wrapper = \Drupal::service('stream_wrapper_manager')->getScheme($file_object->getFileUri());
// 20220212
// Get and save remote file inside node file field.
$file_url = 'FILE_URL_HERE';
$filename = pathinfo($file_url);
$new_filename = 'imported-' . $filename['filename'];

$new_file_folder_uri = 'private://import';
$new_file_uri = $new_file_folder_uri . '/' . $new_filename . '.jpg';
$file_content = file_get_contents($file_url);

// Important step to create folder if not exists.
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$file_system->prepareDirectory($new_file_folder_uri, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);

$file = file_save_data($file_content, $new_file_uri);
if ($file) {
  $node = Node::load(1);
  $node->set('field_logo', $file->id());
  $node->save();
}
else {
  // Failed to save the file.
}


// Check if remote file exists
function remoteFileExists($url) {
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_NOBODY, true);
    $result = curl_exec($curl);
    $ret = false;
    if ($result !== false) {
      // if request was ok, check response code
      $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

      if ($statusCode == 200) {
        $ret = true;
      }
    }

    curl_close($curl);
    return $ret;
}
// 20220214
// Getting theme path programmatically.
/** @var \Drupal\Core\Extension\ThemeHandler $theme_handler */
$theme_handler = \Drupal::service('theme_handler');
$default_theme = $theme_handler->getDefault();
$specific_theme_path = $theme_handler->getTheme('THEME_NAME')->getPath();

/** @var \Drupal\Core\Theme\ThemeManager $theme_manager */
$theme_manager = \Drupal::theme();

/** @var \Drupal\Core\Theme\ActiveTheme $active_theme */
$active_theme = $theme_manager->getActiveTheme();
global $base_url;
$default_user_photo = $base_url.'/'. $active_theme->getPath() .'/images/user.png';
// 20220214
// Getting view row data in view field twig file (views-view-field.html.twig) or (views-view-field--field-nr-workflow.html.twig)
{{ view.field.field_nr_workflow.original_value }}
{{ view.field.field_nr_workflow.value(view.result[row.index]) }}
{{ data.description.plain|slice(0, 60) }}

For more: https://www.drupal.org/docs/theming-drupal/twig-in-drupal/discovering-and-inspecting-variables-in-twig-templates
// 20220215
// mobile_number field
  $allowed_countries['SA'] = 'SA';
  $allowed_countries['AE'] = 'AE';
  $allowed_countries['BH'] = 'BH';
  $allowed_countries['KW'] = 'KW';
  $allowed_countries['OM'] = 'OM';
  $allowed_countries['QA'] = 'QA';
  $form['field_u_mobile']['widget'][0]['#required'] = TRUE;
  $form['field_u_mobile']['widget'][0]['#default_value']['country'] = 'SA';
  $form['field_u_mobile']['widget'][0]['#mobile_number'] = [
    'allowed_countries' => $allowed_countries,
    'verify' => \Drupal\mobile_number\MobileNumberUtilInterface::MOBILE_NUMBER_VERIFY_NONE,
    'message' => 'Your verification code from !site_name: !code',
    'tfa' => FALSE,
    'token_data' => [],
    'placeholder' => '05xxxxxxxx',
  ];
// 20220216
// Twig print full URL in Twig template
{{ url('view.VIEW_NAME.DISPLAY_NAME', {'arg_0': 1}) }}
// Submit form with no validations
// Ignore form validation
// '#limit_validation_errors' => array(),
    $form['actions'] = ['#type' => 'actions'];
    $form['actions']['back'] = [
      '#type' => 'submit',
      // '#button_type' => 'primary',
      '#value' => $this->t('Back'),
      '#submit' => ['::previousForm'],
      '#limit_validation_errors' => [],
      '#validate' => [],
    ];
// 20220310
// Validate email value
if (!\Drupal::service('email.validator')->isValid($value)) {
  $form_state->setError($element, t('The email address %mail is not valid.', ['%mail' => $value]));
}
// 20220328
// Hide page title block for specific routes.
// Inject Drupal 8 block programmatically.
/**
 * Implements template_preprocess_page().
 */
function MYMODULE_preprocess_page(&$variables) {
  // Hide page title for specific routes.
  $route_name = \Drupal::routeMatch()->getRouteName();
  $routes = [
    'ROUTE_NAME',
  ];
  if (in_array($route_name, $routes)) {
    unset($variables['page']['content']['THEMENAME_page_title']);
  }
}
// 20220331
// PHPCS
lando composer --dev require squizlabs/php_codesniffer
lando composer --dev require drupal/coder
lando composer --dev require slevomat/coding-standard

./vendor/bin/phpcs --standard=Drupal,DrupalPractice --extensions=php,module,inc,install,test,profile,theme,js,css,info,txt,md --runtime-set installed_paths /app/vendor/drupal/coder/coder_sniffer,/app/vendor/slevomat/coding-standard
// 20220406
// Lando disable annoying update reminders:
lando --channel none
// 20220410
// Getting timestamp from a date field value.
// Getting date object from date field value.
/** @var \Drupal\Core\Datetime\DrupalDateTime $date_object */
$date_object = $node->field_date->date;
$date_object->format('Y/m/d');
$date_object->getTimestamp()
// Redirect the page response and respecting the cacheability metadata to avoid "leaked cacheability metadata".
  $front_url = Url::fromRoute('view.aliens.list', [], ['absolute' => TRUE])->toString();
  $response = new \Drupal\Core\Cache\CacheableResponse($front_url, \Symfony\Component\HttpFoundation\Response::HTTP_OK);
  $response->addCacheableDependency($front_url);
  return $response;
// 20220419
// Inject twig template inside view header
        $add_new = [
          '#theme' => 'template_name_here',
        ];
        $add_new = render($add_new);
        $options = [
          'id' => 'area',
          'table' => 'views',
          'field' => 'area',
          'relationship' => 'none',
          'group_type' => 'none',
          'admin_label' => '',
          'empty' => TRUE,
          'tokenize' => NULL,
          'content' => [
            'value' => $add_new,
            'format' => 'raw', // This is the text format you need to have `raw` text format.
          ],
          'plugin_id' => 'text',
        ];
        $view->setHandler($display_id, 'header', 'area', $options);
// cURL
$url = '';
$curl = curl_init();
    curl_setopt_array($curl, array(
      CURLOPT_URL => $url,
      CURLOPT_POST => 1,
      CURLOPT_POSTFIELDS => [
        'name' => 'hi',
      ],
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_ENCODING => "",
      CURLOPT_MAXREDIRS => 10,
      CURLOPT_TIMEOUT => 60,
      CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
      //CURLOPT_CUSTOMREQUEST => 'POST',
      CURLOPT_SSL_VERIFYHOST => 0 ,
      CURLOPT_SSL_VERIFYPEER => 0 ,
      CURLOPT_HTTPHEADER => [
        'Authorization: Bearer AA',
      ],
    ));

    $response = curl_exec($curl);
    $response = json_decode($response);
    $err = curl_error($curl);
    curl_close($curl);


$client = new \GuzzleHttp\Client(['base_uri' => 'https://api/v4']);
  $response = $client->request('POST', '/accounts', [
    'headers' => [
      'Authorization' => 'Bearer AAAA',
    ],
    'multipart' => [
      [
        'name'     => 'file',
        'contents' => $file_contents
      ],
    ]
  ]);
// drupal manage private file access
/**
 * Implements hook_entity_access().
 */
function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
  if ($entity->getEntityTypeId() == 'file') {
    if ($account->hasPermission('developer')) {
      return AccessResult::allowed();
    }
  }

  return AccessResult::neutral();
}
// Return #markup in RAW HTML code with no restrictions.
use Drupal\Core\Render\Markup;
return [
  '#markup' => Markup::create($html),
];
// Require JS /libraries into /web/libraries folder
1. `composer require oomphinc/composer-installers-extender`
1. add the following to your composer.json file into the repositories section:
```
{
  "type": "composer",
  "url": "https://asset-packagist.org"
}
```
1. It's also needed to extend the 'installer-path' section:
```
    "web/libraries/{$name}": [
        "type:drupal-library",
        "type:bower-asset",
        "type:npm-asset"
    ],
```
1. And add a new 'installer-types' section next to the 'installer-path' in the 'extra' section: `"installer-types": [ "bower-asset", "npm-asset" ],` into 
1. Now you can download libraries like: `composer install npm-asset/select2` .. you need to pick the right package name, you can browse packages from here: https://asset-packagist.org/

----

Helpful Resources:
- https://www.bounteous.com/insights/2020/04/22/guide-loading-external-javascript-drupal/
- https://www.drupal.org/project/slick/issues/2855190
- Description of select2 contrib module: https://www.drupal.org/node/1638186/revisions/12029663/view
- https://git.drupalcode.org/project/webform/-/blob/8.x-5.x/composer.libraries.json
- https://www.drupal.org/docs/8/modules/webform/webform-frequently-asked-questions/how-to-use-composer-to-install-libraries
- https://github.com/acquia/acquia-ra-composer/blob/master/composer-templates/composer-libraries.json
- Different approach: https://github.com/balbuf/drupal-libraries-installer
// drush ev '\Drupal::entityTypeManager()->getStorage("shortcut_set")->load("default")->delete();'

فضلاً إذا أعجبتك هذه الصفحة لاتنسى أن تقوم بمشاركتها