3
0
Fork 0
mirror of https://github.com/farmOS/farmOS.git synced 2024-02-23 11:37:38 +01:00
farmOS/farm_log.module
2015-05-27 16:31:33 -04:00

685 lines
18 KiB
Plaintext

<?php
/**
* @file
* Code for the Farm Log feature.
*/
include_once 'farm_log.features.inc';
/**
* Implements hook_permission().
*/
function farm_log_permission() {
return array(
'view farm logs' => array(
'title' => t('View farm logs'),
'description' => t('View all farm-related log items.'),
),
);
}
/**
* Implements hook_farm_admin_actions().
*/
function farm_log_farm_admin_actions() {
// Define farm area actions.
$actions = array(
'activity' => array(
'title' => t('Add an activity'),
'href' => 'log/add/farm_activity',
'assets' => array(
'all',
),
'views' => array(
'farm_log_activity',
),
'paths' => array(
'farm',
'farm/plan',
'taxonomy/term/%',
),
),
'movement' => array(
'title' => t('Add a movement'),
'href' => 'log/add/farm_movement',
'assets' => array(
'all',
),
'views' => array(
'farm_log_movement',
),
),
'observation' => array(
'title' => t('Add an observation'),
'href' => 'log/add/farm_observation',
'assets' => array(
'all',
),
'views' => array(
'farm_log_observation',
),
'paths' => array(
'farm',
'farm/plan',
'taxonomy/term/%',
),
),
);
return $actions;
}
/**
* Implements hook_farm_taxonomy_term_view_views().
*/
function farm_log_farm_taxonomy_term_view_views($term) {
// If the term is not an area, bail.
if ($term->vocabulary_machine_name != 'farm_areas') {
return array();
}
// Return a list of Views to include on Areas.
return array(
// Activities in this area.
array(
'name' => 'farm_log_activity',
'arg' => 2,
),
// Observations in this area.
array(
'name' => 'farm_log_observation',
'arg' => 2,
),
// Area asset history (at the bottom).
array(
'name' => 'farm_area_assets',
'weight' => 100,
),
);
}
/**
* Implements hook_farm_area_links().
*/
function farm_log_farm_area_links($id) {
return array(
array(
'title' => t('Activities'),
'href' => 'taxonomy/term/' . $id,
'options' => array(
'fragment' => 'Activities',
),
'weight' => -100,
),
array(
'title' => t('Observations'),
'href' => 'taxonomy/term/' . $id,
'options' => array(
'fragment' => 'Observations',
),
'weight' => -90,
),
);
}
/**
* Implements hook_entity_view_alter().
*/
function farm_log_entity_view_alter(&$build, $type) {
/*
* Alter farm assets to display their current location.
*/
// If it's not a farm_asset, bail.
if ($type != 'farm_asset') {
return;
}
// If the entity information isn't available, bail.
if (empty($build['#entity'])) {
return;
}
$asset = $build['#entity'];
// Start an output string.
$output = '<strong>Current location:</strong> ';
// Get the asset's location.
$area = farm_log_asset_location($asset);
// If a location was found, add a link to it.
if (!empty($area->tid)) {
$output .= l($area->name, 'taxonomy/term/' . $area->tid);
}
// Otherwise, none.
else {
$options = array(
'query' => array(
'destination' => 'farm/asset/' . $asset->id,
'farm_asset' => $asset->id,
),
);
$link = l(t('add a movement'), 'log/add/farm_movement', $options);
$output .= 'N/A (' . $link . ')';
}
// Add it to the build array.
$build['location'] = array(
'#markup' => $output,
'#weight' => -100,
);
}
/**
* Implements hook_form_alter().
*/
function farm_log_form_alter(&$form, &$form_state, $form_id) {
// If this is a log form...
if ($form_id == 'log_form') {
// If there is an asset(s) reference field.
if (!empty($form['field_farm_asset'])) {
// Alter the form using our helper function.
// ($asset is used below to for movement logs.)
$asset = farm_log_form_prepopulate_asset($form, 'field_farm_asset', TRUE);
}
// If there is an area(s) reference field...
if (!empty($form['field_farm_area'])) {
// Alter the form with the farm_log helper function.
farm_log_form_prepopulate_area($form, 'field_farm_area');
}
// If this is the farm_movement...
if ($form['#bundle'] == 'farm_movement') {
// If no asset was found above, don't continue.
if (empty($asset)) {
return;
}
// If the "from" field is empty...
if (empty($form['field_farm_move_from'][LANGUAGE_NONE][0]['#default_value'])) {
// Look up the asset's last location and prepopulate the "from" field.
$area = farm_log_asset_location($asset);
if (!empty($area->name)) {
$form['field_farm_move_from'][LANGUAGE_NONE]['#default_value'] = $area->name;
}
}
}
}
// Or, if this is a farm_asset form.
elseif ($form_id == 'farm_asset_form') {
// Get the farm asset entity from the form.
$asset = $form['farm_asset']['#value'];
// Get the asset's current location.
$location = farm_log_asset_location($asset);
// Add a field for setting the asset's current location.
$form['farm_log_asset_location'] = array(
'#type' => 'textfield',
'#title' => t('Current location'),
'#description' => t('Set the current location of this asset. Asset location is determined by movement logs, so a movement log will automatically be generated if you change this field.'),
'#autocomplete_path' => 'taxonomy/autocomplete/field_farm_area',
'#default_value' => !empty($location->name) ? $location->name : '',
);
$form['actions']['submit']['#submit'][] = 'farm_log_asset_location_submit';
}
}
/**
* Submit handler for processing the asset location field.
*
* @param array $form
* The form array.
* @param array $form_state
* The form state array.
*/
function farm_log_asset_location_submit(array $form, array &$form_state) {
// Only proceed if farm_log_asset_location has a value.
if (empty($form_state['values']['farm_log_asset_location'])) {
return;
}
// Only proceed if the value is not the default value.
if ($form_state['values']['farm_log_asset_location'] == $form['farm_log_asset_location']['#default_value']) {
return;
}
// If an asset doesn't exist, bail.
if (empty($form_state['values']['farm_asset'])) {
return;
}
// Grab the asset.
$asset = $form_state['values']['farm_asset'];
// Explode the value into an array and only take the first value.
// (Same behavior as taxonomy autocomplete widget.)
$values = explode(',', $form_state['values']['farm_log_asset_location']);
$value = trim(reset($values));
// If the value is empty, bail.
if (empty($value)) {
return;
}
// Attempt to look up the area by it's name.
$areas = taxonomy_get_term_by_name($value, 'farm_areas');
$area = reset($areas);
// If an area was not found, create a new one.
if (empty($area)) {
$farm_areas = taxonomy_vocabulary_machine_name_load('farm_areas');
$area = new stdClass();
$area->name = $value;
$area->vid = $farm_areas->vid;
taxonomy_term_save($area);
}
// Create a movement log.
farm_log_move_assets($asset, $area->tid, REQUEST_TIME, TRUE);
}
/**
* Find the location of an asset.
*
* @param FarmAsset $asset
* The farm_asset object to look for.
* @param int $time
* Unix timestamp limiter. Only movement logs before this time will be
* included. Defaults to the current time. Set to 0 to load the absolute last.
* @param bool $done
* Whether or not to only show movement logs that are marked as "done".
* Defaults to TRUE.
*
* @return area
* Returns the area that the asset is in.
*/
function farm_log_asset_location(FarmAsset $asset, $time = REQUEST_TIME, $done = TRUE) {
$area = NULL;
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'log')
->entityCondition('bundle', 'farm_movement')
->fieldCondition('field_farm_asset', 'target_id', $asset->id)
->propertyOrderBy('timestamp', 'DESC')
->propertyOrderBy('id', 'DESC')
->range(0, 1);
if (!empty($time)) {
$query->propertyCondition('timestamp', $time, '<=');
}
if (!empty($done)) {
$query->propertyCondition('done', TRUE);
}
$result = $query->execute();
if (!empty($result['log'])) {
foreach ($result['log'] as $id => $entity) {
$log = log_load($id);
if (!empty($log->field_farm_move_to[LANGUAGE_NONE][0]['tid'])) {
$term = taxonomy_term_load($log->field_farm_move_to[LANGUAGE_NONE][0]['tid']);
if (!empty($term)) {
$area = $term;
break;
}
}
}
}
return $area;
}
/**
* Build a query to find the latest movement log of an asset.
*
* @param int|string $asset_id
* The asset id to search for. This can either be a specific id, or a field
* alias string from another query (ie: 'mytable.assetid'). For an example
* of field alias string usage, see the Views field handler code in
* farm_log_handler_relationship_location::query().
* @param bool $done
* Whether or not to include only logs that are done. Defaults to TRUE.
* @param bool $future
* Whether or not to include logs with a timestamp in the future. Defaults to
* FALSE.
*
* @return \SelectQuery
* Returns a SelectQuery for finding the latest log.
*/
function farm_log_asset_movement_query($asset_id, $done = TRUE, $future = FALSE) {
// Build a sub-query that will be used in the join to load the latest
// movement log of a given asset.
$query = db_select('log', 'ss_log');
$query->join('field_data_field_farm_asset', 'ss_fdffa', 'ss_log.id = ss_fdffa.entity_id');
$query->where("ss_log.type = 'farm_movement'");
$query->where('ss_fdffa.field_farm_asset_target_id = ' . $asset_id);
$query->where('ss_fdffa.deleted = 0');
$query->orderBy('ss_log.timestamp', 'DESC');
$query->orderBy('ss_log.id', 'DESC');
$query->range(0, 1);
$query->addField('ss_log', 'id');
// If only "done" movement logs should be included, add a filter.
if ($done) {
$query->where('ss_log.done = 1');
}
// If future logs should not be included, then limit to only logs that
// have a date before right now.
if (!$future) {
$query->where('ss_log.timestamp <= ' . REQUEST_TIME);
}
// Return the query object.
return $query;
}
/**
* Helper function for enabling asset prepopulation in log forms.
*
* @param array $form
* The form array to modify, passed by reference.
* @param string $field_name
* The machine name of the entity reference field that should be populated.
* @param bool $tags
* Whether or not the field is using the "Tags style" entity reference
* widget. Defaults to FALSE.
*
* @return FarmAsset farm_asset
* Returns the asset object, if found.
*/
function farm_log_form_prepopulate_asset(array &$form, $field_name = 'field_farm_asset', $tags = FALSE) {
$asset = NULL;
// The location of the field's default value depends on whether or not it is
// a "Tags style" entity reference field.
if (empty($tags)) {
$field_value = &$form[$field_name][LANGUAGE_NONE][0]['target_id']['#default_value'];
}
else {
$field_value = &$form[$field_name][LANGUAGE_NONE]['#default_value'];
}
// If the "farm_asset" query parameter is set...
$params = drupal_get_query_parameters();
if (!empty($params['farm_asset'])) {
// Verify that the farm_asset is valid.
$asset = farm_asset_load($params['farm_asset']);
if ($asset) {
// Add the asset to the form.
$form['farm_asset'] = array(
'#type' => 'value',
'#value' => $asset,
);
// Prepopulate the asset reference field.
if (empty($field_value)) {
$field_value = entity_label('farm_asset', $asset) . ' (' . $asset->id . ')';
}
}
}
// If the asset field is not empty, hide it so that it can't be changed, and
// display them as plain text in a fieldset at the top.
if (!empty($field_value)) {
$form[$field_name]['#access'] = FALSE;
$form[$field_name . '_markup'] = array(
'#type' => 'fieldset',
'#title' => t('Assets'),
'#description' => $field_value,
'#weight' => -100,
);
}
return $asset;
}
/**
* Helper function for enabling area prepopulation in log forms.
*
* @param array $form
* The form array to modify, passed by reference.
* @param string $field_name
* The machine name of the term reference field that should be populated.
*
* @return TaxonomyTerm term
* Returns the taxonomy term object, if found.
*/
function farm_log_form_prepopulate_area(array &$form, $field_name = 'field_farm_area') {
$area = NULL;
// Alias for the field's default value.
$field_value = &$form[$field_name][LANGUAGE_NONE]['#default_value'];
// If the "farm_area" query parameter is set...
$params = drupal_get_query_parameters();
if (!empty($params['farm_area'])) {
// Verify that the farm_area is valid.
$area = taxonomy_term_load($params['farm_area']);
if ($area) {
// Add the area to the form.
$form['farm_area'] = array(
'#type' => 'value',
'#value' => $area,
);
// Prepopulate the area reference field.
if (empty($field_value)) {
$field_value = entity_label('taxonomy_term', $area);
}
}
}
return $area;
}
/**
* Implements hook_action_info().
*/
function farm_log_action_info() {
return array(
'farm_log_asset_move_action' => array(
'type' => 'farm_asset',
'label' => t('Move'),
'configurable' => TRUE,
'triggers' => array('any'),
'aggregate' => TRUE,
),
);
}
/**
* Asset move action configuration form.
*
* @param array $context
* The action context array.
* @param array $form_state
* The form state array.
*
* @return array
* Returns a form array.
*/
function farm_log_asset_move_action_form(array $context, array $form_state) {
// Add Javascript to improve UX.
drupal_add_js(drupal_get_path('module', 'farm_log') . '/js/move_action.js');
// Build a list of the assets being moved.
if (!empty($form_state['selection'])) {
$assets = array();
$query = db_select('farm_asset', 'a');
$query->addField('a', 'name');
$query->condition('a.id', $form_state['selection']);
$results = $query->execute();
foreach ($results as $result) {
$assets[] = $result->name;
}
// If there is more than one asset, theme an item list.
if (count($assets) > 1) {
$markup = theme('item_list', array('items' => $assets, 'title' => t('Move Assets:')));
}
// Otherwise, display the one.
else {
$markup = '<h3>' . t('Move') . ' ' . reset($assets) . '</h3>';
}
// Display the asset(s) in the form.
$form['assets'] = array(
'#type' => 'markup',
'#markup' => $markup,
);
}
// "To" field: select list of areas.
$form['to'] = array(
'#type' => 'select',
'#title' => t('To'),
'#options' => taxonomy_allowed_values(field_info_field('field_farm_move_to')),
'#required' => TRUE,
);
// Convert the timestamp to the format Date API expects.
$default_value = date('Y-m-d H:i', REQUEST_TIME);
// "Date" field: default to current date.
$form['timestamp'] = array(
'#type' => 'date_select',
'#title' => t('Date'),
'#date_format' => 'M j Y',
'#date_type' => DATE_FORMAT_UNIX,
'#date_year_range' => '-10:+3',
'#default_value' => $default_value,
'#required' => TRUE,
);
// "Done" field: mark movements as done.
$form['done'] = array(
'#type' => 'checkbox',
'#title' => t('Movement is done'),
'#description' => t('Check this if the movement has already been done. Otherwise, you will need to mark the movement log item as done later.'),
'#default_value' => TRUE,
);
return $form;
}
/**
* Asset move action configuration form submit.
*
* @param array $form
* The form array.
* @param array $form_state
* The form state array.
*
* @return array
* Returns an array of variables to pass to the action function.
*/
function farm_log_asset_move_action_submit(array $form, array $form_state) {
return array(
'to' => $form_state['values']['to'],
'timestamp' => $form_state['values']['timestamp'],
'done' => $form_state['values']['done'],
);
}
/**
* Action function for farm_log_asset_move_action.
*
* Creates a new movement record for the specified assets.
*
* @param array $assets
* An array of asset entities to move.
* @param array $context
* Array with parameters for this action.
*/
function farm_log_asset_move_action(array $assets, $context = array()) {
// Assemble parameters.
$area_id = $context['to'];
$timestamp = (!empty($context['timestamp'])) ? strtotime($context['timestamp']) : REQUEST_TIME;
$done = (!empty($context['done'])) ? TRUE : FALSE;
// Delegate to the helper function.
farm_log_move_assets($assets, $area_id, $timestamp, $done);
}
/**
* Move farm asset(s) to an area. Creates a movement log.
*
* @param array|FarmAsset $assets
* Array of assets to include in the move.
* @param int $area_id
* The id of the area to move to.
* @param int $timestamp
* The timestamp of the move.
* @param bool $done
* Whether or not to mark the movement done. Default to FALSE.
*/
function farm_log_move_assets($assets, $area_id, $timestamp, $done = FALSE) {
// If $assets isn't an array, wrap it.
if (!is_array($assets)) {
$assets = array($assets);
}
// Create a new movement log entity.
$log = entity_create('log', array('type' => 'farm_movement'));
// Keep track of what areas these assets are coming from.
$from_areas = array();
// Iterate through the assets.
foreach ($assets as $asset) {
// Add the asset to the asset reference field.
$log->field_farm_asset[LANGUAGE_NONE][] = array(
'target_id' => $asset->id,
);
// Load the asset's current location.
$area = farm_log_asset_location($asset);
// If the asset has a current location, add it to the "from" field.
// Avoid adding the same area more than once.
if (!empty($area->name) && !empty($area->tid) && !in_array($area->tid, $from_areas)) {
$log->field_farm_move_from[LANGUAGE_NONE][] = array(
'tid' => $area->tid,
);
$from_areas[] = $area->tid;
}
}
// Set the date.
$log->timestamp = $timestamp;
// Set the "to" area.
$log->field_farm_move_to[LANGUAGE_NONE][] = array(
'tid' => $area_id,
);
// Set the log's done status.
$log->done = $done;
// Save the movement.
log_save($log);
}