You are here

farm_quantity_log.module in farmOS 7

Farm quantity log module.

File

modules/farm/farm_quantity/farm_quantity_log/farm_quantity_log.module
View source
<?php

/**
 * @file
 * Farm quantity log module.
 */

/**
 * Extract quantity data from a log, with optional filters for measure/label.
 *
 * @param Log $log
 *   The log object to extract quantity information from.
 * @param string $measure
 *   The quantity measure to search for (ie: weight).
 * @param string $label
 *   The quantity label to search for.
 *
 * @return array
 *   Returns a structured array of information about the quantities recorded
 *   on the log.
 */
function farm_quantity_log_data(Log $log, $measure = NULL, $label = NULL) {

  // Start with an empty data array.
  $data = array();

  // Load the log entity metadata wrapper.
  $log_wrapper = entity_metadata_wrapper('log', $log);

  // If there are no quantities, bail.
  if (empty($log_wrapper->field_farm_quantity)) {
    return $data;
  }

  // Iterate over the quantities.
  foreach ($log_wrapper->field_farm_quantity as $quantity) {

    // If a measure is specified, and it doesn't match, skip this one.
    if (!empty($measure) && $quantity->field_farm_quantity_measure
      ->value() != $measure) {
      continue;
    }

    // If a label is specified, and it doesn't match, skip this one.
    if (!empty($label) && $quantity->field_farm_quantity_label
      ->value() != $label) {
      continue;
    }

    // Get the quantity value and convert to a decimal.
    $value = '';
    if (!empty($quantity->field_farm_quantity_value
      ->value())) {
      if (!empty($quantity->field_farm_quantity_value
        ->value()['fraction'])) {
        $value = $quantity->field_farm_quantity_value
          ->value()['fraction']
          ->toDecimal(0, TRUE);
      }
    }

    // Get the quantity units name.
    $units = '';
    if (!empty($quantity->field_farm_quantity_units
      ->value())) {
      if (!empty($quantity->field_farm_quantity_units
        ->value()->name)) {
        $units = $quantity->field_farm_quantity_units
          ->value()->name;
      }
    }

    // Add quantity data to the array.
    $data[] = array(
      'measure' => $quantity->field_farm_quantity_measure
        ->value(),
      'value' => $value,
      'units' => $units,
      'label' => $quantity->field_farm_quantity_label
        ->value(),
    );
  }

  // Return the data.
  return $data;
}

/**
 * Load logs for an asset with a given quantity measure and/or label.
 *
 * @param FarmAsset $asset
 *   The farm_asset object to look for.
 * @param string $measure
 *   The quantity measure to search for (ie: weight).
 * @param string $label
 *   The quantity label to search for.
 * @param int $time
 *   Unix timestamp limiter. Only logs before this time will be included.
 *   Defaults to the current time. Set to 0 to load the absolute last.
 * @param bool|null $done
 *   Whether or not to only show logs that are marked as "done". TRUE will limit
 *   to logs that are done, and FALSE will limit to logs that are not done. If
 *   this is set to NULL, no filtering will be applied. Defaults to TRUE.
 * @param string $type
 *   The log type to filter by. If empty, no filtering will be applied.
 * @param bool $single
 *   Whether or not to limit the query to a single result. Defaults to TRUE.
 *
 * @return Log|array|bool
 *   Returns a log entity, or an array of them. FALSE if something goes wrong.
 */
function farm_quantity_log_asset(FarmAsset $asset, $measure = NULL, $label = NULL, $time = REQUEST_TIME, $done = TRUE, $type = NULL, $single = TRUE) {

  // If the asset doesn't have an ID (for instance if it is new and hasn't been
  // saved yet), bail.
  if (empty($asset->id)) {
    return FALSE;
  }

  // Make a query for loading the latest quantity log.
  $query = farm_quantity_log_asset_query($asset->id, $measure, $label, $time, $done, $type, $single);

  // Execute the query and gather the log id.
  $result = $query
    ->execute();

  // Return array of log objects. $single = FALSE
  if (empty($single)) {
    $log_item_ids = $result
      ->fetchCol();
    $logs = entity_load('log', $log_item_ids);
    return $logs;
  }
  else {
    if (!empty($single)) {
      $log_id = $result
        ->fetchField();
      if (!empty($log_id)) {
        return log_load($log_id);
      }
    }
  }

  // If all else fails, return FALSE.
  return FALSE;
}

/**
 * Build a query to find logs of an asset that defines a quantity.
 *
 * @param int $asset_id
 *   The asset id to search for.
 * @param string $measure
 *   The quantity measure to search for (ie: weight).
 * @param string $label
 *   The quantity label to search for.
 * @param int $time
 *   Unix timestamp limiter. Only logs before this time will be included.
 *   Defaults to the current time. Set to 0 to load the absolute last.
 * @param bool|null $done
 *   Whether or not to only show logs that are marked as "done". TRUE will limit
 *   to logs that are done, and FALSE will limit to logs that are not done. If
 *   this is set to NULL, no filtering will be applied. Defaults to TRUE.
 * @param string|null $type
 *   The log type to filter by. If this is NULL, no filtering will be applied.
 * @param bool $single
 *   Whether or not to limit the query to a single result. Defaults to TRUE.
 *
 * @return \SelectQuery
 *   Returns a SelectQuery object.
 */
function farm_quantity_log_asset_query($asset_id, $measure = NULL, $label = NULL, $time = REQUEST_TIME, $done = TRUE, $type = NULL, $single = TRUE) {

  /**
   * Please read the comments in farm_log_asset_query() to understand how this
   * works, and to be aware of the limitations and responsibilities we have in
   * this function with regard to sanitizing query inputs.
   */

  // Use the farm_log_asset_query() helper function to start a query object.
  $query = farm_log_asset_query($asset_id, $time, $done, $type, $single);

  // Add a query tag to identify where this came from.
  $query
    ->addTag('farm_quantity_log_asset_query');

  // Add quantity filters to the query using a helper function.
  farm_quantity_log_query_add_filters($query, $measure, $label);

  // Return the query object.
  return $query;
}

/**
 * Load all quantity logs that match certain criteria.
 *
 * @param string $measure
 *   The quantity measure to search for (ie: weight).
 * @param string $label
 *   The quantity label to search for.
 * @param int $start_time
 *   Unix timestamp limiter. Only logs after this time will be included.
 *   Defaults to 0, which will not limit the logs at all.
 * @param int $end_time
 *   Unix timestamp limiter. Only logs before this time will be included.
 *   Defaults to the current time. Set to 0 to load the absolute last.
 * @param bool|null $done
 *   Whether or not to only show logs that are marked as "done". TRUE will limit
 *   to logs that are done, and FALSE will limit to logs that are not done. If
 *   this is set to NULL, no filtering will be applied. Defaults to TRUE.
 * @param string|null $type
 *   The log type to filter by. If this is NULL, no filtering will be applied.
 * @param string $category
 *   The log category to search for.
 *
 * @return array
 *   Returns an array of log entities.
 */
function farm_quantity_log($measure = NULL, $label = NULL, $start_time = 0, $end_time = REQUEST_TIME, $done = TRUE, $type = NULL, $category = NULL) {

  // Make a query for loading quantity logs.
  $query = farm_quantity_log_query($measure, $label, $start_time, $end_time, $done, $type, $category);

  // Execute the query and gather the log ids.
  $result = $query
    ->execute();
  $log_ids = array();
  foreach ($result as $row) {
    if (!empty($row->id)) {
      $log_ids[] = $row->id;
    }
  }

  // If there are log IDs, load the logs.
  if (!empty($log_ids)) {
    return log_load_multiple($log_ids);
  }
  return array();
}

/**
 * Build a query to find logs that define quantity measurements.
 *
 * @param string $measure
 *   The quantity measure to search for (ie: weight).
 * @param string $label
 *   The quantity label to search for.
 * @param int $start_time
 *   Unix timestamp limiter. Only logs after this time will be included.
 *   Defaults to 0, which will not limit the logs at all.
 * @param int $end_time
 *   Unix timestamp limiter. Only logs before this time will be included.
 *   Defaults to the current time. Set to 0 to load the absolute last.
 * @param $done
 *   Whether or not to only show logs that are marked as "done". TRUE will limit
 *   to logs that are done, and FALSE will limit to logs that are not done. If
 *   any other value is used, no filtering will be applied. Defaults to TRUE.
 * @param string|null $type
 *   The log type to filter by. If this is NULL, no filtering will be applied.
 * @param string $category
 *   The log category to search for.
 *
 * @return \SelectQuery
 *   Returns a SelectQuery object.
 */
function farm_quantity_log_query($measure = NULL, $label = NULL, $start_time = 0, $end_time = REQUEST_TIME, $done = TRUE, $type = NULL, $category = NULL) {

  /**
   * Please read the comments in farm_log_query() to understand how this works,
   * and to be aware of the limitations and responsibilities we have in this
   * function with regard to sanitizing query inputs.
   */

  // Use the farm_log_query() helper function to start a query object.
  $query = farm_log_query($end_time, $done, $type, FALSE);

  // Add a query tag to identify where this came from.
  $query
    ->addTag('farm_quantity_log_query');

  // Add quantity filters to the query using a helper function.
  farm_quantity_log_query_add_filters($query, $measure, $label);

  // Ensure $start_time is valid, because it may be used directly in the query
  // string. This is defensive code. See note about views_join_subquery above.
  // Similar logic is used for the $end_time in farm_log_query().
  // In this case, we want to make sure that it is numeric AND that it is not
  // greater than the end time.
  if (!is_numeric($start_time) || $start_time > $end_time) {
    $start_time = 0;
  }

  // If $start_time is not zero, limit to only logs after it. This allows the
  // absolute first log to be found by setting $start_time to zero.
  // Similar logic is used for the $end_time in farm_log_query().
  if ($start_time !== 0) {
    $query
      ->where('ss_log.timestamp >= ' . $start_time);
  }

  // If $category is not empty, load the category ID, then join in the log
  // category field data and limit the query to logs with a matching category.
  if (!empty($category)) {
    $category_term = farm_term($category, 'farm_log_categories', FALSE);
    if (!empty($category_term->tid)) {
      $query
        ->innerJoin('field_data_field_farm_log_category', 'ss_fdfflc', "ss_fdfflc.entity_type = 'log' AND ss_fdfflc.entity_id = ss_log.id AND ss_fdfflc.deleted = 0");
      $query
        ->where("ss_fdfflc.field_farm_log_category_tid = '" . $category_term->tid . "'");
    }
  }

  // Return the query object.
  return $query;
}

/**
 * Helper function for adding joins and filters to a quantity log query.
 *
 * @param \SelectQuery $query
 *   The query object to alter.
 * @param string $measure
 *   The quantity measure to search for (ie: weight).
 * @param string $label
 *   The quantity label to search for.
 */
function farm_quantity_log_query_add_filters(&$query, $measure = NULL, $label = NULL) {

  // Ensure that $measure and $label are valid strings, because we use them
  // directly in the query's WHERE statements below. This is defensive code.
  // See note about views_join_subquery in farm_log_asset_query().
  if (!is_null($measure)) {
    $measures = farm_quantity_measure_options();
    if (!array_key_exists($measure, $measures)) {
      $measure = '';
    }
  }
  if (!is_null($label)) {
    $label = db_like($label);
  }

  // Add the log ID field.
  $query
    ->addField('ss_log', 'id');

  // Join in the Quantity field collection. Use an inner join to exclude logs
  // that do not have quantity field collection attached.
  $query
    ->innerJoin('field_data_field_farm_quantity', 'ss_fdffq', "ss_fdffq.entity_type = 'log' AND ss_fdffq.entity_id = ss_log.id AND ss_fdffq.deleted = 0");

  // Filter to only include logs with a matching measure. Use an inner join to
  // exclude logs that do not have a measure.
  if (!empty($measure)) {
    $query
      ->innerJoin('field_data_field_farm_quantity_measure', 'ss_fdffqm', "ss_fdffqm.entity_id = ss_fdffq.field_farm_quantity_value AND ss_fdffqm.deleted = 0");
    $query
      ->where("ss_fdffqm.field_farm_quantity_measure_value = '" . $measure . "'");
  }

  // Filter to only include logs with a matching label. Use an inner join to
  // exclude logs that do not have a label.
  if (!empty($label)) {
    $query
      ->innerJoin('field_data_field_farm_quantity_label', 'ss_fdffql', "ss_fdffql.entity_id = ss_fdffq.field_farm_quantity_value AND ss_fdffql.deleted = 0");
    $query
      ->where("ss_fdffql.field_farm_quantity_label_value = '" . $label . "'");
  }
}

/**
 * Helper function for creating a farm quantity measurement log.
 *
 * @param string $type
 *   The log type machine name.
 * @param string $name
 *   Optionally specify a name for the new log.
 * @param int $timestamp
 *   The timestamp of the log (defaults to REQUEST_TIME).
 * @param bool $done
 *   Boolean indicating whether or not the log is done.
 * @param array $assets
 *   An array of assets to reference in the log.
 * @param array $measurements
 *   An array of measurements to add to the log. Example:
 *     $measurements = array(
 *       array(
 *         'measure' => 'weight',
 *         'value' => 100,
 *         'units' => 'lbs',
 *         'label' => 'Foo',
 *       ),
 *     );
 * @param string $notes
 *   Notes to add to the log.
 * @param array $categories
 *   An array of categories to add to the log.
 *
 * @return \Log
 *   Returns a saved log entity.
 */
function farm_quantity_log_create($type, $name = '', $timestamp = REQUEST_TIME, $done = TRUE, $assets = array(), $measurements = array(), $notes = '', $categories = array()) {

  // Create a new log entity.
  $log = farm_log_create($type, $name, $timestamp, $done, $assets, $notes, $categories);

  // Add quantity measurements.
  farm_quantity_log_add_measurements($log, $measurements);

  // Return the log.
  return $log;
}

/**
 * Helper function for adding quantity measurements to a log.
 *
 * @param \Log $log
 *   A log entity.
 * @param array $measurements
 *   An array of measurements to add to the log. Example:
 *     $measurements = array(
 *       array(
 *         'measure' => 'weight',
 *         'value' => 100,
 *         'units' => 'lbs',
 *         'label' => 'Foo',
 *       ),
 *     );
 */
function farm_quantity_log_add_measurements($log, $measurements) {

  // If the log is not valid, or the measurements are empty, bail.
  if (empty($log->id) || empty($measurements)) {
    return;
  }

  // Iterate through the measurements.
  foreach ($measurements as $measurement) {

    // Create a new quantity field_collection entity attached to the log.
    $quantity = entity_create('field_collection_item', array(
      'field_name' => 'field_farm_quantity',
    ));
    $quantity
      ->setHostEntity('log', $log);

    // Create an entity wrapper for the quantity.
    $quantity_wrapper = entity_metadata_wrapper('field_collection_item', $quantity);

    // Set the quantity measure, if available.
    if (!empty($measurement['measure'])) {
      $quantity_wrapper->field_farm_quantity_measure
        ->set($measurement['measure']);
    }

    // Set the quantity value, if available.
    if (isset($measurement['value'])) {
      $value_fraction = fraction_from_decimal($measurement['value']);
      $quantity_wrapper->field_farm_quantity_value->numerator
        ->set($value_fraction
        ->getNumerator());
      $quantity_wrapper->field_farm_quantity_value->denominator
        ->set($value_fraction
        ->getDenominator());
    }

    // Set the units, if available.
    if (!empty($measurement['units'])) {

      // Load/create units term.
      $units_term = farm_term($measurement['units'], 'farm_quantity_units');

      // Set the quantity units.
      $quantity_wrapper->field_farm_quantity_units = $units_term;
    }

    // Set the label, if available.
    if (!empty($measurement['label'])) {
      $quantity_wrapper->field_farm_quantity_label
        ->set($measurement['label']);
    }

    // Save the quantity.
    $quantity_wrapper
      ->save();
  }
}

/**
 * Helper function for updating the value of a quantity measurement on a log,
 * based on its label.
 *
 * @param \Log $log
 *   A log entity.
 * @param string $label
 *   The label of the quantity measurement that needs updating.
 * @param string|float $value
 *   The new quantity measurement value.
 */
function farm_quantity_log_update_measurement_by_label($log, $label, $value) {

  // Load the log entity metadata wrapper.
  $log_wrapper = entity_metadata_wrapper('log', $log);

  // If there are no quantities, bail.
  if (empty($log_wrapper->field_farm_quantity)) {
    return;
  }

  // Iterate over the quantities.
  foreach ($log_wrapper->field_farm_quantity as $quantity) {

    // If a label matches, update it.
    if ($quantity->field_farm_quantity_label
      ->value() == $label) {

      // Clear the old value.
      $quantity->field_farm_quantity_value = array();

      // Add the new value.
      $value_fraction = fraction_from_decimal($value);
      $quantity->field_farm_quantity_value->numerator
        ->set($value_fraction
        ->getNumerator());
      $quantity->field_farm_quantity_value->denominator
        ->set($value_fraction
        ->getDenominator());

      // Save the quantity.
      $quantity
        ->save();
    }
  }
}

/**
 * Helper function for deleting a quantity measurement from a log, based on its
 * label.
 *
 * @param \Log $log
 *   A log entity.
 * @param string $label
 *   The label of the quantity measurement that should be deleted.
 */
function farm_quantity_log_delete_measurement_by_label($log, $label) {

  // Load the log entity metadata wrapper.
  $log_wrapper = entity_metadata_wrapper('log', $log);

  // If there are no quantities, bail.
  if (empty($log_wrapper->field_farm_quantity)) {
    return;
  }

  // Iterate over the quantities.
  foreach ($log_wrapper->field_farm_quantity as $key => $quantity) {

    // If the label matches, delete it.
    if ($quantity->field_farm_quantity_label
      ->value() == $label) {
      entity_delete('field_collection_item', $quantity->item_id
        ->value());
      unset($log->field_farm_quantity[LANGUAGE_NONE][$key]);
      log_save($log);
    }
  }
}

Functions

Namesort descending Description
farm_quantity_log Load all quantity logs that match certain criteria.
farm_quantity_log_add_measurements Helper function for adding quantity measurements to a log.
farm_quantity_log_asset Load logs for an asset with a given quantity measure and/or label.
farm_quantity_log_asset_query Build a query to find logs of an asset that defines a quantity.
farm_quantity_log_create Helper function for creating a farm quantity measurement log.
farm_quantity_log_data Extract quantity data from a log, with optional filters for measure/label.
farm_quantity_log_delete_measurement_by_label Helper function for deleting a quantity measurement from a log, based on its label.
farm_quantity_log_query Build a query to find logs that define quantity measurements.
farm_quantity_log_query_add_filters Helper function for adding joins and filters to a quantity log query.
farm_quantity_log_update_measurement_by_label Helper function for updating the value of a quantity measurement on a log, based on its label.