You are here

SimpleMathField.php in Views Simple Math Field 8

Same filename and directory in other branches
  1. 8.2 src/Plugin/views/field/SimpleMathField.php

File

src/Plugin/views/field/SimpleMathField.php
View source
<?php

namespace Drupal\views_simple_math_field\Plugin\views\field;

use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\field\NumericField;
use Drupal\views\ResultRow;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * @file
 * Defines Drupal\views_simple_math_field\Plugin\views\field\SimpleMathField.
 */

/**
 * Field handler to complete mathematical operation.
 *
 * @ingroup views_field_handlers
 * @ViewsField("field_views_simple_math_field")
 */
class SimpleMathField extends NumericField implements ContainerFactoryPluginInterface {
  protected $entityTypeManager;

  /**
   * SimpleMathField constructor.
   *
   * @param array $configuration
   * @param $plugin_id
   * @param $plugin_definition
   * @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManager $entityTypeManager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * Sets the initial field data at zero.
   */
  public function query() {
  }

  /**
   * {@inheritdoc}
   */
  protected function defineOptions() {
    $options = parent::defineOptions();

    // Give this field and alias
    $this->field_alias = 'field_views_simple_math_field';
    $options['fieldset_one']['default'] = NULL;
    $options['fieldset_two']['default'] = NULL;
    $options['fieldset_one']['data_field_one'] = [
      'default' => NULL,
    ];
    $options['fieldset_two']['data_field_two'] = [
      'default' => NULL,
    ];
    $options['operation'] = [
      'default' => NULL,
    ];
    $options['fieldset_one']['constant_one'] = [
      'default' => NULL,
    ];
    $options['fieldset_two']['constant_two'] = [
      'default' => NULL,
    ];
    $options['percentage'] = [
      'default' => NULL,
    ];
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);
    $fieldDelta = preg_replace('[\\D]', '', $this->options['id']);
    $fieldList = $this->displayHandler
      ->getFieldLabels();
    foreach ($fieldList as $key => $value) {
      if ($this->field_alias === $key && $fieldDelta < preg_replace('[\\D]', '', $key)) {
        unset($fieldList[$key]);
      }
    }
    unset($fieldList[$this->options['id']]);
    $fieldList['const'] = t('Enter a constant');
    $form['fieldset_one'] = [
      '#type' => 'fieldset',
      '#title' => t('Select the field representing the first value.'),
      '#collapsible' => FALSE,
      '#collapsed' => FALSE,
      '#weight' => -10,
      '#required' => TRUE,
    ];
    $form['fieldset_one']['data_field_one'] = [
      '#type' => 'radios',
      '#title' => t('Data Field One'),
      '#options' => $fieldList,
      '#default_value' => $this->options['fieldset_one']['data_field_one'],
      '#weight' => -10,
    ];
    $form['fieldset_one']['constant_one'] = [
      '#type' => 'textfield',
      '#title' => t('Constant Value'),
      '#default_value' => $this->options['fieldset_one']['constant_one'],
      '#states' => [
        'visible' => [
          ':input[name="options[fieldset_one][data_field_one]"]' => [
            'value' => 'const',
          ],
        ],
      ],
      '#weight' => -9,
    ];
    $form['fieldset_two'] = [
      '#type' => 'fieldset',
      '#collapsible' => FALSE,
      '#collapsed' => FALSE,
      '#title' => t('Select the field representing the second value.'),
      '#weight' => -8,
      '#required' => TRUE,
    ];
    $form['fieldset_two']['data_field_two'] = [
      '#type' => 'radios',
      '#title' => t('Data Field Two'),
      '#options' => $fieldList,
      '#default_value' => $this->options['fieldset_two']['data_field_two'],
      '#weight' => -8,
    ];
    $form['fieldset_two']['constant_two'] = [
      '#type' => 'textfield',
      '#title' => t('Constant Value'),
      '#default_value' => $this->options['fieldset_two']['constant_two'],
      '#states' => [
        'visible' => [
          ':input[name="options[fieldset_two][data_field_two]"]' => [
            'value' => 'const',
          ],
        ],
      ],
      '#weight' => -7,
    ];
    $form['operation'] = [
      '#type' => 'radios',
      '#title' => t('Operation'),
      '#options' => [
        '+' => t('Add'),
        '-' => t('Subtract'),
        '*' => t('Multiply'),
        '/' => t('Divide'),
        '%' => t('Modulo'),
        '**' => t('Power'),
      ],
      '#default_value' => $this->options['operation'],
      '#description' => t('Choose your operation.'),
      '#weight' => -6,
      '#required' => TRUE,
    ];
    $form['percentage'] = [
      '#type' => 'checkbox',
      '#title' => t('Convert to percent'),
      '#default_value' => $this->options['percentage'],
      '#description' => t('Multiplies the result by 100'),
      '#weight' => -5,
      '#states' => [
        'visible' => [
          ':input[name="options[operation]"]' => [
            'value' => '/',
          ],
        ],
      ],
    ];
    return $form;
  }

  /**
   * Determine the field type we are dealing with.
   *
   * @param $field
   *
   * @return string
   */
  protected function getFieldType($field) {
    $field_handler = $this->displayHandler
      ->getHandler('field', $field)->options;
    if (!empty($field_handler['type'])) {
      $field_type = $field_handler['type'];
    }
    else {
      $field_type = 'undefined';
    }
    return $field_type;
  }

  /**
   * Determine if the field comes from a relationship.
   *
   * @param $field
   *
   * @return mixed
   */
  protected function getFieldRelationship($field) {
    $field_handler = $this->displayHandler
      ->getHandler('field', $field)->options;
    if (!empty($field_handler['relationship']) && $field_handler['relationship'] !== 'none') {
      $relationship = $field_handler['relationship'];
    }
    else {
      $relationship = NULL;
    }
    return $relationship;
  }

  /**
   * Determine if the field is rewritten/altered.
   *
   * @param $field
   *
   * @return mixed
   */
  protected function getRewriteStatus($field) {
    $field_handler = $this->displayHandler
      ->getHandler('field', $field)->options;
    if ($field_handler['alter']['alter_text'] && !empty($field_handler['alter']['text'])) {
      $alter = $field_handler['alter']['text'];
    }
    else {
      $alter = NULL;
    }
    return $alter;
  }

  /**
   * @param $values
   * @param $field
   * @param $relationship
   *
   * @return \Drupal\Core\Entity\EntityInterface|null
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function getRelationshipEntity($values, $field, $relationship) {
    $relationship_entity = NULL;

    // Get the entity type of the relationship.
    $relationship_entity_type = $this->displayHandler
      ->getHandler('field', $field)
      ->getEntityType();
    $relationship_entities = $values->_relationship_entities;

    // First check the referenced entity.
    if (isset($relationship_entities[$relationship])) {

      // Get the id of the relationship entity.
      $entity_id = $relationship_entities[$relationship]
        ->id();

      // Get the data of the relationship entity.
      $relationship_entity = $this->entityTypeManager
        ->getStorage($relationship_entity_type)
        ->load($entity_id);
    }
    return $relationship_entity;
  }

  /**
   * Get the value of a simple math field.
   *
   * @param ResultRow $values
   *    Row results.
   * @param \Drupal\Core\Entity\EntityInterface|null $entity
   *   The current row entity.
   * @param bool $fieldOne
   *   Whether we are fetching field one's value.
   *
   * @return mixed
   *   The field value.
   *
   * @throws \Exception
   */
  protected function getFieldValue(ResultRow $values, $entity, $fieldOne) {
    if (!empty($fieldOne)) {
      $field = $this->options['fieldset_one']['data_field_one'];
    }
    else {
      $field = $this->options['fieldset_two']['data_field_two'];
    }

    // Determine what type of field is being used.
    $field_type = $this
      ->getFieldType($field);

    // If the field is rewritten, get the rewritten text. Else, returns null.
    $rewritten = $this
      ->getRewriteStatus($field);
    $data = NULL;

    // Process if not a Views Simple Math field constant.
    if ($field !== 'const') {

      // Process if not undefined.
      if ($field_type !== 'undefined') {

        // Get the value of a field that comes from a relationship.
        $relationship = $this
          ->getFieldRelationship($field);
        if ($relationship) {

          // Use the relationship's entity to fetch the field value.
          $entity = $this
            ->getRelationshipEntity($values, $field, $relationship);
        }

        // The next two statements handle fields with or without a relationship.
        if (isset($entity) && $rewritten) {

          // If already numeric, there is no need for advancedRender().
          if (is_numeric($rewritten) == TRUE) {
            $data = $rewritten;
          }
          else {
            $data = $this->view->field[$field]
              ->advancedRender($values);
          }
        }
        if (isset($entity) && !$rewritten) {
          $field_base = $this->displayHandler
            ->getHandler('field', $field)->field;
          if ($entity
            ->hasField($field_base)) {
            $data = $entity
              ->get($field_base)
              ->getValue()[0]['value'];
          }

          // For Commerce fields.
          if ($field_type === 'commerce_price_default' || $field_type === 'commerce_product_variation') {
            $commerce_field_id = $this->displayHandler
              ->getHandler('field', $field)->options['id'];
            if ($commerce_field_id === 'list_price__number') {
              $data = $entity
                ->get('list_price')
                ->getValue()[0]['number'];
            }
            if ($commerce_field_id === 'price__number') {
              $data = $entity
                ->get('price')
                ->getValue()[0]['number'];
            }
          }
        }
      }
      else {
        $data = $this->view->field[$field]
          ->getValue($values);
        if ($rewritten) {
          if (\Drupal::routeMatch()
            ->getRouteName() == 'entity.view.preview_form') {
            \Drupal::service('messenger')
              ->addMessage(t('Views Simple Math Field sometimes has difficulty rendering the correct value for rewritten fields. You may want to double check that field ID <em>@field</em> is properly outputting a value.', [
              '@field' => $field,
            ]), 'warning');
          }

          // Use current() to ensure result is a string.
          $data = current($this->displayHandler
            ->getHandler('field', $field)
            ->advancedRender($values));
          return $data;
        }

        // If a Views Simple Math Field, ensure the value is numeric.
        if (strpos($field, 'field_views_simple_math_field') === 0) {

          // If a separator is used, remove it before performing the math.
          if (!empty($this->options['separator'])) {
            $data = $this->view->field[$field]
              ->getValue($values);
            $separator = $this->options['separator'];
            if (strpos($data, $separator)) {
              $data = str_replace($separator, '', $data);
            }
          }
          else {
            $data = $this->view->field[$field]
              ->getValue($values);
            if (strpos($data, ',')) {
              $data = str_replace(',', '', $data);
            }
            if (strpos($data, ' ')) {
              $data = str_replace(' ', '', $data);
            }
          }
        }
      }
    }
    else {
      if (!empty($fieldOne)) {
        $data = $this->options['fieldset_one']['constant_one'];
      }
      else {
        $data = $this->options['fieldset_two']['constant_two'];
      }
    }

    // There's no value. Default to 0.
    if (!isset($data)) {
      $data = 0;
    }
    return $data;
  }

  /**
   * {@inheritdoc}
   * @throws \Exception
   */
  public function getValue(ResultRow $values, $field = NULL) {
    parent::getValue($values, $field);
    $operation = $this->options['operation'];
    $entity = $this
      ->getEntity($values);
    $dataFieldOneValue = $this
      ->getFieldValue($values, $entity, TRUE);
    $dataFieldTwoValue = $this
      ->getFieldValue($values, $entity, FALSE);
    if ($operation === '+') {
      $value = $dataFieldOneValue + $dataFieldTwoValue;
    }
    elseif ($operation === '-') {
      $value = $dataFieldOneValue - $dataFieldTwoValue;
    }
    elseif ($operation === '*') {
      $value = $dataFieldOneValue * $dataFieldTwoValue;
    }
    elseif ($operation === '/') {
      $value = $dataFieldOneValue / $dataFieldTwoValue;
      if ($this->options['percentage'] === 1) {
        $value = $value * 100;
      }
    }
    elseif ($operation === '%') {
      $value = $dataFieldOneValue % $dataFieldTwoValue;
    }
    elseif ($operation === '**') {
      $value = pow($dataFieldOneValue, $dataFieldTwoValue);
    }
    else {
      $value = NULL;
    }
    return $value;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition, $container
      ->get('entity_type.manager'));
  }

}

Classes

Namesort descending Description
SimpleMathField Field handler to complete mathematical operation.