migmag-1.0.x-dev/migmag_process/src/Plugin/migrate/process/MigMagCompare.php

migmag_process/src/Plugin/migrate/process/MigMagCompare.php
<?php

declare(strict_types=1);

namespace Drupal\migmag_process\Plugin\migrate\process;

use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;

/**
 * Migrate process plugin for comparing two values.
 *
 * Using this plugin in combination of the 'skip_on_empty' process plugin may
 * allow you to skip evaluation of process pipelines if a specific condition is
 * or is not met.
 *
 * Configuration options:
 * - operator: The comparison operator to use. Defaults to '===' (identical).
 *   For available options check PHP documentation.
 * - return_if: The array of the return values. By default, the process plugin
 *   returns boolean FALSE if the comparison fails, or TRUE if it passes. Except
 *   in case of the spaceship operator ('<=>'), which returns integer 0,
 *   a negative integer, or a positive integer. If we need a NULL return
 *   value if the comparison evaluates to FALSE, then we should specify this
 *   configuration as ['false' => 'foo_bar_baz']. Optional.
 * - multiple: whether the plugin should handle multiple values or not.
 *   Optional, defaults to FALSE.
 *
 * Examples:
 *
 * @code
 * destination_property:
 *   plugin: migmag_compare
 *   source:
 *     - property_1
 *     - property_2
 * @endcode
 *
 * This configuration sets 'destination_property' to boolean TRUE if
 * 'property_1' is identical to 'property_2', and will set it to
 * boolean FALSE if 'property_1' and 'property_2' have different values.
 *
 * @code
 * destination_property:
 *   plugin: migmag_compare
 *   source:
 *     - property_1
 *     - property_2
 *   operator: '>='
 *   return_if:
 *     false: 'false'
 *     true: 'true'
 * @endcode
 *
 * This configuration sets 'destination_property' to string 'true' if
 * 'property_1' is greater than or equals to 'property_2'; or it sets it to
 * string 'false' if 'property_1' is less than 'property_2'.
 *
 * @code
 * destination_property:
 *   plugin: migmag_compare
 *   source:
 *     - property_1
 *     - property_2
 *   operator: '<=>'
 *   return_if:
 *     '-1': '1st less than 2nd'
 *     '0': 'equal'
 *     '1': '1st greater than 2nd'
 * @endcode
 *
 * With this configuration, 'destination_property' will be set to:
 * - '1st less than 2nd' if 'property_1' is less than 'property_2',
 * - 'equal' if 'property_1' equals to 'property_2',
 * - '1st greater than 2nd' if 'property_1' is greater than 'property_2'.
 *
 * @code
 * destination_property:
 *   -
 *     plugin: migmag_compare
 *     source:
 *       - property_1
 *       - property_2
 *   -
 *     plugin: skip_on_empty
 *     method: process
 *   -
 *     plugin: get
 *     source: property_3
 *   [...]
 * @endcode
 *
 * - If the value of 'property_1' isn't identical to 'property_2', then
 *   'migmag_compare' returns boolean FALSE. Since this is an empty value,
 *   'skip_on_empty' will stop the execution of the process plugin pipeline.
 * - If the value of 'property_1' and 'property_2' are identical,
 *   'migmag_compare' returns boolean TRUE. 'skip_on_empty' won't do anything,
 *   and the pipeline continues with the next process plugin (which returns
 *   the value of 'property_3').
 *
 * @see https://www.php.net/manual/en/language.operators.comparison.php
 *
 * @MigrateProcessPlugin(
 *   id = "migmag_compare"
 * )
 */
class MigMagCompare extends ProcessPluginBase {

  /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    if (!is_array($value)) {
      throw new MigrateException(
        sprintf(
          "'%s' migrate process plugin's processed value must be an array, got '%s'.",
          $this->pluginId,
          gettype($value)
        )
      );
    }
    if (count($value) < 2) {
      throw new MigrateException(
        sprintf(
          "'%s' migrate process plugin's processed array value must have at least two values.",
          $this->pluginId
        )
      );
    }
    [$variable_1, $variable_2] = array_values($value);
    $operator = $this->configuration['operator'] ?? '===';
    if (!is_string($operator)) {
      throw new MigrateException(
        sprintf(
          "'%s' migrate process plugin's operator must be a string, got '%s'.",
          $this->pluginId,
          gettype($operator)
        )
      );
    }

    try {
      $comparison_result = $this->doCompare($variable_1, $variable_2, $operator);
    }
    catch (\Throwable $t) {
      throw new MigrateException(
        sprintf(
          "Comparison failed in '%s' migrate process plugin with message: %s.",
          $this->pluginId,
          $t->getMessage()
        )
      );
    }

    if (!isset($comparison_result)) {
      throw new MigrateException(
        sprintf(
          "'%s' migrate process plugin does not support operator '%s'.",
          $this->pluginId,
          $operator
        )
      );
    }

    return $this->deliverReturnValue($comparison_result);
  }

  /**
   * Evaluated the configured comparison.
   *
   * @param mixed $value_1
   *   The first value of the comparison.
   * @param mixed $value2
   *   The second value of the comparison.
   * @param string $operator
   *   The operator to use.
   *
   * @return bool|int|null
   *   The return value of the comparison, ot NULL if the operator is
   *   unsupported.
   */
  protected function doCompare($value_1, $value2, string $operator) {
    switch ($operator) {
      case '==':
        return $value_1 == $value2;

      case '===':
        return $value_1 === $value2;

      case '!=':
      case '<>':
        return $value_1 <> $value2;

      case '!==':
        return $value_1 !== $value2;

      case '<':
        return $value_1 < $value2;

      case '<=':
        return $value_1 <= $value2;

      case '>':
        return $value_1 > $value2;

      case '>=':
        return $value_1 >= $value2;

      case '<=>':
        return $value_1 <=> $value2;
    }

    return NULL;
  }

  /**
   * Returns the appropriate configured value.
   *
   * @param bool|int $comparison_result
   *   The result of an evaluated comparison.
   *
   * @return bool|int|mixed
   *   The returned value.
   */
  protected function deliverReturnValue($comparison_result) {
    // Spaceship returns integer.
    if (is_bool($comparison_result)) {
      return $comparison_result === FALSE
        ? $this->configuration['return_if']['false'] ?? $comparison_result
        : $this->configuration['return_if']['true'] ?? $comparison_result;
    }

    if (!is_int($comparison_result)) {
      throw new \BadMethodCallException(
        sprintf(__METHOD__ . ": argument must be a boolean or an integer")
      );
    }

    // This must be an integer since only spaceship returns non-boolean values.
    if ($comparison_result > 0) {
      return $this->configuration['return_if']['1'] ?? $comparison_result;
    }
    if ($comparison_result < 0) {
      return $this->configuration['return_if']['-1'] ?? $comparison_result;
    }

    return $this->configuration['return_if']['0'] ?? $comparison_result;
  }

  /**
   * {@inheritdoc}
   */
  public function multiple() {
    return $this->configuration['multiple'] ?? FALSE;
  }

}

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

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