reviewer-1.2.x-dev/modules/reviewer_test_kit/src/Plugin/reviewer/Task/Entity/Display/FieldPluginsTaskBase.php

modules/reviewer_test_kit/src/Plugin/reviewer/Task/Entity/Display/FieldPluginsTaskBase.php
<?php

declare(strict_types=1);

namespace Drupal\reviewer_test_kit\Plugin\reviewer\Task\Entity\Display;

use Drupal\Core\Entity\Display\EntityDisplayInterface;
use Drupal\reviewer\Reviewer\Result\ResultInterface;
use Drupal\reviewer\Reviewer\Status\Status;
use Drupal\reviewer\Reviewer\Task\FixableInterface;

/**
 * Internal task for checking if fields on entity displays use allowed plugins.
 *
 * @internal
 *   This class is internal and the methods within may change at any time. Use
 *   \Drupal\reviewer_test_kit\Plugin\reviewer\Task\Entity\Display\Form\FieldWidgetsTaskBase
 *   or
 *   \Drupal\reviewer_test_kit\Plugin\reviewer\Task\Entity\Display\View\FieldFormatterTaskBase
 *   to check if fields use the correct plugins on specific entity displays
 *   instead.
 *
 * @see \Drupal\reviewer_test_kit\Plugin\reviewer\Task\Entity\Display\Form\FieldWidgetsTaskBase
 * @see \Drupal\reviewer_test_kit\Plugin\reviewer\Task\Entity\Display\View\FieldFormatterTaskBase
 */
abstract class FieldPluginsTaskBase extends DisplayFieldsTaskBase implements FixableInterface {

  /**
   * The types of fields to check.
   *
   * The field types are the field definition types defined in the field
   * storage, not the field widget or formatter plugin types. This is because
   * the widget and formatter plugin types are what are checked by this task. To
   * check all fields, set the value to ['*'].
   *
   * Entity reference fields often do not convey enough information for tasks to
   * accurately check the field based on type alone, because the correct
   * behavior is often dependent on the type of handler and bundle of the entity
   * referenced. In this case, you may specify the handler as the array key. You
   * may also specify handler bundles using a pipe followed by a comma-separated
   * list.
   *
   * For example, to check all entity reference media fields use
   * ['default:media' => 'entity_reference'], and to check only image and icon
   * media fields use ['default:media|icon,image' => 'entity_reference'].
   *
   * Do not access this directly in tasks, but use the fieldsToCheck() method to
   * return a list of fields from the $fieldNames and $fieldTypes properties
   * evaluated for a specific entity display.
   *
   * A \LogicException will be thrown if this property and $fieldNames are both
   * empty.
   *
   * @var array<int|string, string>
   *
   * @see \Drupal\Core\Field\FieldDefinitionInterface
   * @see \Drupal\reviewer_test_kit\Plugin\reviewer\Task\Entity\Display\DisplayTaskBase
   */
  protected array $fieldTypes = [];

  /**
   * A list of field widget or formatter plugins allowed for use on the field.
   *
   * @var string[]
   */
  protected array $allowedPlugins = [];

  /**
   * {@inheritdoc}
   */
  protected function checkValidProperties(): void {
    parent::checkValidProperties();

    if (\count($this->allowedPlugins) === 0) {
      throw new \LogicException(sprintf('%s::allowedPlugins cannot be empty.', static::class));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function check(): ResultInterface {
    $this->checkValidProperties();

    $results = $this->createCollection();
    foreach ($this->displays() as $display) {
      $components = $display->getComponents();

      foreach ($this->fieldsToCheck($display) as $field) {
        $results->add($this->createCheckResult(
          \in_array($components[$field]['type'] ?? '', $this->allowedPlugins, TRUE),
          sprintf('Field "%s" uses an appropriate plugin.', $field),
          sprintf('Field "%s" plugin must be one of: "%s".', $field, implode('", "', $this->allowedPlugins)),
          "{$display->getMode()}.$field",
        ));
      }
    }

    return $results;
  }

  /**
   * {@inheritdoc}
   */
  public function fix(): ResultInterface {
    if (\count($this->allowedPlugins) > 1) {
      return $this->createFixResult(
        Status::Fail,
        '',
        sprintf('Cannot set field plugins on "%s" because there is more than one allowed plugin ("%s").', $this->entityTypeFullId(), implode('", "', $this->allowedPlugins)),
      );
    }

    $allowed = reset($this->allowedPlugins);

    foreach ($this->displays() as $display) {
      $components = $display->getComponents();

      foreach ($this->fieldsToCheck($display) as $field) {
        if (($components[$field]['type'] ?? '') !== $allowed) {
          $components[$field]['type'] = $allowed;
        }

        $this->fixSaveCallback($display, $field, $components[$field]);
      }

      $display->save();
    }

    return $this->createFixResult(
      $this->check()->getStatus(),
      sprintf('Fixed field plugins for "%s".', $this->entityTypeFullId()),
      sprintf('Unable to fix field plugins for "%s".', $this->entityTypeFullId()),
    );
  }

  /**
   * Get all field names matching the field type and optional handler.
   *
   * @return string[]
   */
  protected function fieldNamesFromTypes(EntityDisplayInterface $display): array {
    // We can short-circuit here if types are empty or all types are matched.
    if (!$this->fieldTypes) {
      return [];
    }

    if ($this->fieldTypes === ['*']) {
      return array_keys($this->fieldsCallback($display));
    }

    $fields_to_check = $this->fieldsCallback($display);

    // Order the types so those without handlers come first. This helps later
    // to not load field definitions to check handlers unless it's necessary.
    $field_types = $this->fieldTypes;
    ksort($field_types);

    foreach ($fields_to_check as $field_name => $configuration) {
      $field_definition = NULL;

      foreach ($field_types as $handler => $field_type) {
        // Get the field definition it doesn't exist yet.
        $field_definition ??= $this->fieldDefinition($field_name);

        // Fields without a field definition are not valid matches.
        if (!$field_definition) {
          unset($fields_to_check[$handler]);
          break;
        }

        // This type does not match, so keep looking through the types.
        if ($field_definition->getType() !== $field_type) {
          continue;
        }

        // There is no handler, so the type match is sufficient, because the
        // types have been ordered so that ones with handlers are checked first.
        if (\is_int($handler)) {
          continue;
        }

        // Retrieve the handler and bundles for the field.
        [$handler, $bundles] = array_pad(explode('|', $handler), 2, NULL);

        // The handler does not match, so keep looking through the types.
        if ($field_definition->getSetting('handler') !== $handler) {
          continue;
        }

        // If there are bundles specified, make sure these match as well.
        if ($bundles) {
          $bundles = explode(',', $bundles);
          /** @var array{target_bundles?: string[]} $handler_settings */
          $handler_settings = $field_definition->getSetting('handler_settings');
          $field_bundles = $handler_settings['target_bundles'] ?? [];

          // No bundles are matched on the field, so keep looking through the
          // types.
          if (\count(array_intersect($bundles, $field_bundles)) === 0) {
            continue;
          }
        }

        // The handler and bundles match, so move on to the next field.
        continue 2;
      }

      // There was no handler or bundle match that moved over this field, so it
      // should be removed.
      unset($fields_to_check[$field_name]);
    }

    return array_keys($fields_to_check);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc