mirror of
https://github.com/farmOS/farmOS.git
synced 2024-02-23 11:37:38 +01:00
685 lines
18 KiB
Plaintext
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);
|
|
}
|