Drupal 8

Entity Reference Selection

Entity Reference Selection

To 'alter' what shows in an entity reference selection

Reference https://drupal.stackexchange.com/questions/298105/can-i-create-non-default-entityreferenceselection

In src/Plugin/EntityReferenceSelection

<?php

namespace Drupal\YOUR_MODULE\Plugin\EntityReferenceSelection;

use Drupal\node\Plugin\EntityReferenceSelection\NodeSelection;

/**
 * Provides a query for a node entity reference selection.
 *
 * @EntityReferenceSelection(
 *   id = "YOUR_MODULE_REFERENCE_SELECTION_ID",
 *   label = @Translation("Filter nodes with a specific field value."),
 *   entity_types = {"node"},
 *   group = "YOUR_MODULE_REFERENCE_SELECTION_GROUP",
 *   weight = 1
 * )
 */
class YourModuleEntityReferenceSelection extends NodeSelection {
  /**
   * {@inheritdoc}
   */
  protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
    $query = parent::buildEntityQuery($match, $match_operator);
    $query->condition('field_featured', 1', '=');
    return $query;
  }
}

Admin configuration form with dependency injection

Admin configuration form with dependency injection

When adding a form using Form API, best practice is to use dependency injection when possible. Admin form classes typically 'extend ConfigFormBase'. If you want to add to it, it'll look like this.

 

<?php

namespace Drupal\my_module\Form;

use Drupal\Core\Config\Config;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class myCustomAdminForm.
 *
 * @package Drupal\my_module\Form
 */
class myCustomAdminForm extends ConfigFormBase {
  
  /**
   * @var $configFactory
   */
  protected $configFactory;
  
  /**
   * @var Config $myConfig
   */
  protected $myConfig;

  /**
   * The Messenger service.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;
  
  public function __construct(
    ConfigFactoryInterface $configFactory,
    MessengerInterface $messenger
  ) {
      parent::__construct($configFactory);
      $this->myConfig = $this->config('my_config.settings.my_settings');
      $this->messenger = $messenger;
  }
  
  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('config.factory'),
      $container->get('messenger')
    );
  }
  
    /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return [
      'my_config.settings.my_settings',
    ];
  }
  
  /**
   * This needs to return a string that is the unique ID of your form. Namespace the form ID based on your module's name.
   */
  public function getFormId() {
    return 'my_module_admin_form';
  }
  
  /**
   * This returns a Form API array that defines each of the elements your form is composed of.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
  
  	$form['text_input'] = [
  		'#type' => 'textfield',
  		'#description' => t('Enter data into this field'),
  		'#default_value' => $this->myConfig->get('my_config_values')
  	]
  	
  	return parent::buildForm($form, $form_state);
  
  }
	
  /**
   * Validate the form
   */  
  public function validateForm(array &$form, FormStateInterface $form_state) {
  	$values = $form_state->getValues();
  	if(empty($values['text_input']) {
  		$form_state->setErrorByName('text_input', t('You must enter data into this field.'));
  	}

  }
  
  /**
   * Submit the form
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
  	$values = $form_state->getValues();
  	
  	$this->myConfig->set('my_config_values', $values['text_input']);
  	
  	$this->myConfig->save();
  	
  	$this->messenger->addStatus('Your value has been saved.');
  	
  	parent::submitForm($form, $form_state);
  }

}

Set Message with a link as an argument

Set Message with a link as an argument

Need to output a message with a link in the text?

$link = Link::createFromRoute('Link Title', 'my_module.my_route', [
          'argument' => 'argument value',
        ]);
        
        $m_args = ['%message_link' => $link->toString()];
        
        \Drupal::messenger()->addStatus(t('Here is a message, and here is a link. %message_link', $m_args));

Output Twig Values in console.log

Output Twig Values in console.log

Trying to debug twig? Not rendering? Try this from within your twig file...

<script>console.log({{ _context | json_encode | raw}});</script>

 

Create a simple service

Create a simple service

Also includes dependency injection

MY_MODULE.services.yml

services:
  my_module.cool_service:
    class: Drupal\my_module\Services\CoolService
    arguments: ['@logger.factory']

/src/Services/CoolService.php

<?php

namespace Drupal\my_module\Services;

use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * CoolService returns what you give it in an array.
 */
class CoolService {


  /**
   * Logger Factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $loggerFactory;


  /**
   * Constructs the Cool service.
   *
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
   *   A Guzzle client object.
   */
  public function __construct(LoggerChannelFactoryInterface $loggerFactory) {
    $this->loggerFactory = $loggerFactory->get('my_module');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('logger.factory')
    );
  }

  public function doSomething($someData) {
    $output = [
      'my_data' => $someData;
    ];

    $this->loggerFactory->error('Lets log a message!');
    
    return $output;
  }


}

Calling the service

$coolService = \Drupal::service('my_module.cool_service');

$returnedData = $coolService->doSomething('My Data');

echo $returnedData;

 

Update field values in multiple paragraphs

Update field values in multiple paragraphs

Let's say you have a LOT of paragraphs on your site. (Meaning Drupal Paragraphs contributed module entities).

Now you want to update a field in all of them. Rather than trying to find each and every one within nodes, you can run a simple script to update a field value.

This will simply load all paragraphs of a specific bundle. Then for each one, you update a value then save.

If you have a lot of paragraphs, you may want to run a batch process.

// Load all the paragraph entities of type
$entityManager = \Drupal::entityTypeManager();
$entities = $entityManager
    ->getStorage('paragraph')
    ->loadByProperties(['type' => 'MY_PARAGRAPH_TYPE','status' => 1]);

// Looping through each one and changing a value
// This could/should be set up in a batch process for a lot of items
foreach($entities as $key => $entity) {
    $paragraphStorage = $entityManager->getStorage('paragraph');
    $paragraph = $paragraphStorage->load($key);
    $paragraph->set('field_my_field','MY_NEW_VALUE');
    $paragraph->save();
}

 

Correct Timezone Handling

Correct Timezone Handling

Sometimes when outputting a Drupal date field, it will display in UTC, not in your desired timezone.

You can run the date through a few lines of code to output as desired.

$dt = new \DateTime($date[0]['value'], new \DateTimeZone('UTC'));
$dt->setTimeZone(new \DateTimeZone('America/Los_Angeles'));
$correct_date =  $dt->format('Y-m-d H:i:s');

 

Using Composer to update Core and Modules

Using Composer to update Core and Modules

Oh, Composer.... How you make life so... uhh.... diff-eas-icult

Installing a module from an install that has been set up correctly with composer

composer require drupal/{name_of_contrib_module}