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', ), 'paths' => array( 'farm', 'farm/plan', 'taxonomy/term/%', ), ), '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 = 'Current location: '; // 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 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 a farm_movement... if ($form['#bundle'] == 'farm_movement') { // If the "to" field is empty... if (empty($form['field_farm_move_to'][LANGUAGE_NONE][0]['#default_value'])) { // Alter the form with the farm_log helper function. farm_log_form_prepopulate_area($form, 'field_farm_move_to'); } // 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_observation... elseif ($form['#bundle'] == 'farm_observation') { // If the observation type field is empty, prepopulate it with "General". if (empty($form['field_farm_observation_type'][LANGUAGE_NONE]['#default_value'])) { $form['field_farm_observation_type'][LANGUAGE_NONE]['#default_value'] = t('General'); } } } // 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 . ')'; } } } 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 = '

' . t('Move') . ' ' . reset($assets) . '

'; } // 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); }