xandeadx.ru Блог музицирующего веб-девелопера

DrupalНеобязательное значение одной из дат в раскрытом фильтре по дате с оператором BETWEEN

По умолчанию, если в раскрытом фильтре по дате с оператором between оставить одно из значений пустым, то фильтр будет просто игнорироваться. Виноват в таком поведении метод \Drupal\views\Plugin\views\filter\Date::acceptExposedInput, который возвращает FALSE если хоть одно значение пустое.

Один из способов решить эту проблему:

// src/Plugin/views/filter/DateOptionalFilter.php
 
namespace Drupal\MODULENAME\Plugin\views\filter;
 
use Drupal\views\Plugin\views\filter\Date;
 
class DateOptionalFilter extends Date {
 
  /**
   * {@inheritDoc}
   */

DrupalДобавляем на страницу управления отображением материала поле "Заголовок"

// MODULENAME.module
 
/**
 * Implements hook_entity_base_field_info_alter().
 */
function MODULENAME_entity_base_field_info_alter(array &$fields, EntityTypeInterface $entity_type): void {
  if ($entity_type->id() == 'node') {
    $fields['title']->setDisplayConfigurable('view', TRUE);
  }
}
 
/**
 * Implements hook_entity_type_build().
 */
function MODULENAME_entity_type_build(array &$entity_types): void {
  if (isset($entity_types['node'])) {
    // See https://www.drupal.org/node/3043840

DrupalПлагин блока, генерящий динамический контент с помощью #lazy_builder

Пример плагина блока, выводящий текущее время. Блок будет закэширован один раз, но контент при этом будет всегда актуальный (за исключением случая, когда включён модуль Internal Page Cache и страницу открыл аноним без сессии).

// src/Plugin/Block/CurrentDateBlock.php
 
namespace Drupal\mymodule\Plugin\Block;
 
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Security\TrustedCallbackInterface;
 
/**
 * @Block(
 *   id = "current_date",
 *   admin_label = @Translation("Current date"),
 *   category = @Translation("Custom"),
 * )
 */

DrupalAJAX команда для сброса значений полей формы

Опубликовано
// src/Ajax/FormResetCommand.php
 
namespace Drupal\modulename\Ajax;
 
use Drupal\Core\Ajax\CommandInterface;
 
class FormResetCommand implements CommandInterface {
 
  protected string $form_selector;
 
  public function __construct(string $form_selector) {
    $this->form_selector = $form_selector;
  }
 
  public function render(): array {
    return [
      'command' => 'invoke',
      'selector' => $this->form_selector,
      'method' => 'trigger',
      'args' => ['reset'],
    ];
  }
 
}

Использование:

$response = new AjaxResponse();

DrupalДобавляем возможность использовать токены в адресе получателя контактной формы

Опубликовано

Скоро будет 12 лет, как на drupal.org весит незакрытое ишью с просьбой добавить возможность использовать токены в контактных формах, но воз и ныне там. По традиции фиксим самостоятельно:

// MODULENAME.module
 
/**
 * Implements hook_form_BASE_FORM_ID_alter(): contact_form_form.
 */
function MODULENAME_form_contact_form_form_alter(array &$form, FormStateInterface $form_state) {
  $form['recipients_new'] = [
    '#type' => 'textfield',
    '#title' => $form['recipients']['#title'],

DrupalПрограммное добавление сущностей

Опубликовано

Контент-сущности

Узнать список доступных полей у конкретной контент-сущности можно заглянув в её метод baseFieldDefinitions().

Нода:

$node = \Drupal\node\Entity\Node::create([
  // Required fields
  'type' => 'page', // Node type id
  'title' => 'Example node',
  // Optional fields
  'status' => \Drupal\node\NodeInterface::PUBLISHED,
  'uid' => 0, // User id. 0 - is anonymouse
  'created' => time(),
  'changed' => time(),
  'promote' => \Drupal\node\NodeInterface::NOT_PROMOTED,

DrupalДобавляем возможность указывать тип прогрессбара для ajax ссылок

Опубликовано

Небольшой костыль, который позволит указывать тип прогрессбара ajax-ссылки в атрибуте data-progress-type.

// ajax-progress-type.js
 
(function ($, Drupal) {
 
  /**
   * Override AJAX "beforeSend" callback.
   */
  var originalAjaxBeforeSend = Drupal.Ajax.prototype.beforeSend;
  Drupal.Ajax.prototype.beforeSend = function (xmlhttprequest, options) {
    var $element = $(this.element);
 
    // Set progress type from "data-progress-type" attribute
    // @TODO Remove after close issue https://www.drupal.org/project/drupal/issues/2818463

DrupalТюнинг кэширования блоков с формой

По умолчанию блоки с формами кэшируются только для анонимных пользователей. Для залогинённых же друпал добавляет во все формы элемент form_token со свойством '#cache' => ['max-age' => 0] (тырк), который запрещает кэшировать блок. Чтобы этого избежать и включить кэширование блока для всех, нужно отключить генерацию form_token:

public function buildForm(array $form, FormStateInterface $form_state) {

DrupalКак добавить настройки к блоку, созданному в стороннем модуле (8)

Пример добавления чекбокса в форму настройки всех блоков меню:

// MODULENAME.module
 
/**
 * Implements hook_form_FORM_ID_alter(): block_form.
 */
function MODULENAME_form_block_form_alter(array &$form, FormStateInterface $form_state): void {
  $block_config = $form_state->getFormObject()->getEntity(); /** @var BlockInterface $block_config */
  $block_plugin = $block_config->getPlugin(); /** @var BlockPluginInterface $block_plugin */
 
  if ($block_plugin instanceof SystemMenuBlock) {
    $form['third_party_settings']['MODULENAME']['nofollow'] = [

DrupalАвтоматизированное тестирование готового сайта с помощью Codeception

Опубликовано

Введение

Codeception — это популярный фреймворк для тестирования веб-приложений. Он написан поверх PHPUnit и позволяет более элегантно писать тесты используя методологию BDD.

Поддерживает три вида тестирования:

Unit tests (модульные тесты) — тестирование отдельных php-классов.