You are here

UnitsEntity.class.inc in Units of Measurement 7.2

Definition of UnitsEntity class.

File

includes/UnitsEntity.class.inc
View source
<?php

/**
 * @file
 * Definition of UnitsEntity class.
 */

/**
 * Units of measurement entity class.
 */
class UnitsEntity extends Entity implements UnitsMathematicalExpression {

  /**
   * Decomposition mathematical expression of this unit of measurement.
   *
   * @var UnitsMathematicalExpressionWrapper
   */
  public $decomposition;

  /**
   * Determine physical dimension of this mathematical expression.
   *
   * @return array
   *   Dimension array of this mathematical expression
   */
  public function dimension() {
    return is_object($this->decomposition) ? $this
      ->decompose()
      ->dimension() : array(
      $this
        ->identifier() => 1,
    );
  }

  /**
   * Test whether this mathematical expression includes a dimensionless member.
   *
   * Whether this mathematical expression contains at least 1 dimensionless
   * member.
   *
   * @return bool
   *   Whether this mathematical expression contains at least 1 dimensionless
   *   member
   */
  public function containsDimensionlessMember() {

    // TODO: should we simply return FALSE or we are to actually verify the
    // dimension of this unit?
    $dimension = $this
      ->dimension();
    return empty($dimension);
  }

  /**
   * Format a certain amount of quantity within this mathematical expression.
   *
   * @param float $quantity
   *   Quantity to be formatted
   *
   * @return UnitsMathematicalExpression
   *   Formatted quantity into this mathematical expression. Sometimes the
   *   mathematical expression itself must mutate in order to format the
   *   quantity. So the returned mathematical expression may not necessarily be
   *   the mathematical expression on which this method was invoked. For
   *   example, the expression "unit" would mutate into "1 * unit" in order to
   *   have a dimensionless member and therefore be able to format the $quantity
   */
  public function formatQuantity($quantity) {

    // We expand this unit into "1 * $this" so we have get a dimensionless
    // member that can be formatted. In case this unit decomposes non-linearly,
    // we use "quantity" operator instead of multiplication.
    $operator = $this
      ->isLinear() ? 'multiply' : 'non_linear';
    return units_mathematical_expression_operator_construct(units_get_operator($operator), new UnitsConstantMathematicalExpression(1), $this)
      ->formatQuantity($quantity);
  }

  /**
   * Numerically evaluate this mathematical expression.
   *
   * @return float
   *   Numerical value of this mathematical expression
   */
  public function evaluate() {
    return is_object($this->decomposition) ? $this
      ->decompose()
      ->evaluate() : NULL;
  }

  /**
   * Decompose (simplify) this mathematical expression.
   *
   * @return UnitsMathematicalExpression
   *   Decomposed (simplified) version of this mathematical expression
   */
  public function decompose() {
    if (is_object($this->decomposition)) {
      return $this->decomposition
        ->getExpression()
        ->decompose();
    }
    return $this;
  }

  /**
   * Create inverse decomposition mathematical expression.
   *
   * @return UnitsMathematicalExpression
   *   Inverse decomposition mathematical expression
   */
  public function inverseDecompose() {
    $decomposition = $this
      ->decompose();
    if (!$this
      ->isLinear()) {
      $straight_decomposition = $decomposition;
      $decomposition = new UnitsConstantMathematicalExpression(UNITS_QUANTITY);
      while (get_class($straight_decomposition) == 'UnitsMathematicalOperatorLinear') {
        $operand1 = $straight_decomposition
          ->operand1();
        $operand2 = $straight_decomposition
          ->operand2();
        $operand_to_isolate = strpos($operand1
          ->toPostfix(), UNITS_QUANTITY) !== FALSE ? 1 : 2;
        $decomposition = $straight_decomposition
          ->isolateOperand($decomposition, $operand_to_isolate);
        $straight_decomposition = $operand_to_isolate == 1 ? $operand1 : $operand2;
      }
    }
    return $decomposition;
  }

  /**
   * Represent this mathematical expression in postfix notation.
   *
   * Represent this mathematical expression in postfix (reverse polish)
   * notation.
   *
   * @param array $options
   *   Options regarding how to format this mathematical expression
   *
   * @return string
   *   Postfix (reverse polish) notation representation of this mathematical
   *   expression
   */
  public function toPostfix($options = array()) {
    return $this
      ->identifier();
  }

  /**
   * Represent this mathematical expression in human-friendly infix notation.
   *
   * @param array $options
   *   Options regarding how to format this mathematical expression
   *
   * @return string
   *   Human-friendly formatted version of this mathematical expression taking
   *   into account provided $options
   */
  public function toInfix($options = array()) {
    return $this
      ->identifier();
  }

  /**
   * Whether this expression is linearly decomposable.
   *
   * @return bool
   *   Whether this expression is linearly decomposable, i.e. its decomposition
   *   can be plugged in into another mathematical expression via multiplication
   *   without losing sense
   */
  public function isLinear() {
    $result = db_select('units_mathematical_expression_postfix', 'e')
      ->fields('e', array(
      'value_string',
    ))
      ->condition('mathematical_expression_id', $this->decomposition_mathematical_expression_id)
      ->condition('type', UNITS_TOKEN_TYPE_CONSTANT)
      ->condition('value_string', UNITS_QUANTITY)
      ->execute();
    return $result
      ->rowCount() == 0;
  }

  /**
   * Save the mathematical expression into database.
   *
   * @param int $mathematical_expression_id
   *   If the ID of the mathematical expression is known, under which it should
   *   be saved, provide it here. Otherwise it will be generated automatically
   * @param int $order
   *   Order of this member when the mathematical expression is written down in
   *   postfix notation. Primarily this argument is used for internal purposes
   *
   * @return int
   *   Mathematical expression ID under which this expression has been save in
   *   the database
   */
  public function unitsMathematicalExpressionSave($mathematical_expression_id, &$order) {
    if (!$mathematical_expression_id) {

      // TODO: this should be possible to do as: INSERT INTO ... FROM SELECT ... thereby making unnecessary the transaction.
      // See https://www.drupal.org/node/310079 for more details.
      $transaction = db_transaction();
      $select = db_select('units_mathematical_expression_postfix', 'e');
      $select
        ->addExpression('MAX(e.mathematical_expression_id) + 1', 'mathematical_expression_id');
      $mathematical_expression_id = $select
        ->execute()
        ->fetchField();
      if (!$mathematical_expression_id) {
        $mathematical_expression_id = 1;
      }
    }
    db_insert('units_mathematical_expression_postfix')
      ->fields(array(
      'type' => UNITS_TOKEN_TYPE_UNIT,
      'mathematical_expression_id' => $mathematical_expression_id,
      'value_string' => $this
        ->identifier(),
      'postfix_order' => ++$order,
    ))
      ->execute();
    return $mathematical_expression_id;
  }

}

Classes

Namesort descending Description
UnitsEntity Units of measurement entity class.