farmOS/modules/farm/farm_livestock/farm_livestock.module

739 lines
22 KiB
Plaintext
Raw Normal View History

<?php
/**
* @file
* Code for the Farm Livestock feature.
*/
include_once 'farm_livestock.features.inc';
/**
* Implements hook_farm_ui_entities().
*/
function farm_livestock_farm_ui_entities() {
return array(
'farm_asset' => array(
'animal' => array(
'label' => t('Animal'),
'label_plural' => t('Animals'),
'view' => 'farm_animals',
),
),
'log' => array(
2018-02-22 17:12:24 +01:00
'farm_birth' => array(
'label' => t('Birth record'),
'label_plural' => t('Birth records'),
'view' => 'farm_log_birth',
'farm_asset' => 'animal',
2018-02-22 17:45:08 +01:00
'log_view_asset_arg' => 3,
2018-02-22 17:12:24 +01:00
'weight' => 20,
),
'farm_medical' => array(
'label' => t('Medical record'),
'label_plural' => t('Medical records'),
'view' => 'farm_log_medical',
'farm_asset' => 'animal',
'weight' => 20,
),
),
'taxonomy_term' => array(
'farm_animal_types' => array(
'label' => t('Type'),
'label_plural' => t('Types'),
'view' => 'farm_animal_types',
'farm_asset' => 'animal',
'asset_view_arg' => 2,
),
),
);
}
/**
* Implements hook_farm_area_type_info().
*/
function farm_livestock_farm_area_type_info() {
return array(
'paddock' => array(
'label' => t('Paddock'),
2015-11-02 05:23:41 +01:00
'style' => 'farm_map_style_dark_green',
'weight' => 5,
),
);
}
/**
* Implements hook_farm_log_categories().
*/
function farm_livestock_farm_log_categories() {
// Provide an "Animals" log category.
return array('Animals');
}
/**
* Implements hook_farm_log_categories_populate().
*/
function farm_livestock_farm_log_categories_populate($log) {
$categories = array();
if (in_array($log->type, array('farm_birth', 'farm_medical'))) {
$categories[] = 'Animals';
}
return $categories;
}
/**
* Implements hook_farm_log_prepopulate_reference_fields().
*/
function farm_livestock_farm_log_prepopulate_reference_fields($log_type) {
// Allow field_farm_mother to be prepopulated in birth log forms.
if ($log_type == 'farm_birth') {
return array(
'field_farm_mother' => array(
'entity_type' => 'farm_asset',
'url_param' => 'farm_asset',
),
);
}
}
/**
* Implements hook_farm_log_prepopulate_reference_fields_alter().
*/
function farm_livestock_farm_log_prepopulate_reference_fields_alter(&$fields, $log_type) {
// Do not prepopulate field_farm_asset in birth log forms, because that is
// the children reference field. When the "Add birth record" action is
// clicked, we assume that the user wants to create a birth record from the
// context of a mother animal. So field_farm_mother is prepopulated instead.
// See farm_livestock_farm_log_prepopulate_reference_fields() above.
if ($log_type == 'farm_birth') {
if (!empty($fields['field_farm_asset'])) {
unset($fields['field_farm_asset']);
}
}
}
/**
* Implements hook_feeds_importer_default_alter().
*/
function farm_livestock_feeds_importer_default_alter($importers) {
// Add extra field mappings to animals.
$name = 'farm_asset_animal';
if (!empty($importers[$name])) {
$mappings = array(
array(
'source' => 'Nicknames',
'target' => 'field_farm_animal_nicknames',
'unique' => FALSE,
'language' => 'und',
),
array(
'source' => 'Date of birth',
'target' => 'field_farm_date:start',
'unique' => FALSE,
'language' => 'und',
),
array(
'source' => 'Species/breed',
'target' => 'field_farm_animal_type',
'term_search' => '0',
'autocreate' => 1,
'language' => 'und',
),
array(
'source' => 'Sex',
'target' => 'field_farm_animal_sex',
'unique' => FALSE,
'language' => 'und',
),
array(
'source' => 'Castrated',
'target' => 'field_farm_animal_castrated',
'unique' => FALSE,
'language' => 'und',
),
array(
'source' => 'Tag ID',
'target' => 'field_farm_animal_tag:field_farm_animal_tag_id',
'unique' => FALSE,
'language' => 'und',
),
array(
'source' => 'Tag type',
'target' => 'field_farm_animal_tag:field_farm_animal_tag_type',
'unique' => FALSE,
'language' => 'und',
),
array(
'source' => 'Tag location',
'target' => 'field_farm_animal_tag:field_farm_animal_tag_location',
'unique' => FALSE,
'language' => 'und',
),
);
$importer_mappings =& $importers[$name]->config['processor']['config']['mappings'];
$importer_mappings = array_merge($importer_mappings, $mappings);
}
// Add/alter field mappings on birth logs.
$name = 'log_farm_birth';
if (!empty($importers[$name])) {
// Add Mother ID mapping.
$mappings = array(
array(
'source' => 'Mother ID',
'target' => 'field_farm_mother',
'unique' => FALSE,
'language' => 'und',
),
);
$importer_mappings =& $importers[$name]->config['processor']['config']['mappings'];
$importer_mappings = array_merge($importer_mappings, $mappings);
// Change "Asset IDs" to "Children IDs".
foreach ($importer_mappings as &$mapping) {
if ($mapping['source'] == 'Asset IDs') {
$mapping['source'] = 'Children IDs';
}
}
}
}
/**
* Implements hook_feeds_tamper_default_alter().
*/
function farm_livestock_feeds_tamper_default_alter(&$feeds_tampers) {
// If farm_import is not installed, bail.
if (!module_exists('farm_import')) {
return;
}
// Make species/breed required.
$feeds_tamper = farm_import_feeds_tamper_plugin('farm_asset', 'animal', 'Species/breed', 'required');
$feeds_tampers[$feeds_tamper->id] = $feeds_tamper;
// Convert "male" to "M".
$feeds_tamper = farm_import_feeds_tamper_plugin('farm_asset', 'animal', 'Sex', 'find_replace', array('find' => t('male'), 'replace' => 'M'));
$feeds_tamper->id .= '-male';
$feeds_tamper->weight = 1;
$feeds_tampers[$feeds_tamper->id] = $feeds_tamper;
// Convert "female" to "F".
$feeds_tamper = farm_import_feeds_tamper_plugin('farm_asset', 'animal', 'Sex', 'find_replace', array('find' => t('female'), 'replace' => 'F'));
$feeds_tamper->id .= '-female';
$feeds_tamper->weight = 2;
$feeds_tampers[$feeds_tamper->id] = $feeds_tamper;
// Convert castrated to boolean.
$feeds_tamper = farm_import_feeds_tamper_plugin('farm_asset', 'animal', 'Castrated', 'boolean_default_false');
$feeds_tampers[$feeds_tamper->id] = $feeds_tamper;
// Convert date of birth to a Unix timestamp.
$feeds_tamper = farm_import_feeds_tamper_plugin('farm_asset', 'animal', 'Date of birth', 'strtotime');
$feeds_tampers[$feeds_tamper->id] = $feeds_tamper;
// Explode nicknames to allow multiple values.
$feeds_tamper = farm_import_feeds_tamper_plugin('farm_asset', 'animal', 'Nicknames', 'explode');
$feeds_tampers[$feeds_tamper->id] = $feeds_tamper;
}
/**
* Implements hook_entity_view_alter().
*/
function farm_livestock_entity_view_alter(&$build, $type) {
// If it's not a farm_asset, or if the entity object is not available, bail.
if ($type != 'farm_asset' || empty($build['#entity'])) {
return;
}
// Alias the asset variable.
$asset = $build['#entity'];
// If it isn't an animal asset, bail.
if ($asset->type != 'animal') {
return;
}
// Get the animal's current weight.
$weight = farm_livestock_animal_weight($asset);
// If a weight measurement isn't available, bail.
if (empty($weight)) {
return;
}
// Get the value and the units.
$value = !empty($weight['value']) ? $weight['value'] : '';
$units = !empty($weight['units']) ? $weight['units'] : '';
// Build the weight display.
$output = '<strong>' . t('Weight') . ':</strong> ' . $value . ' ' . $units;
// If the animal has an inventory greater than 1, add "(average)".
$inventory = farm_inventory($asset);
if ($inventory > 1) {
$output .= ' (' . t('average') . ')';
}
// Add it to the build array.
$build['weight'] = array(
'#markup' => $output,
'#prefix' => '<div class="weight">',
'#suffix' => '</div>',
'#weight' => -120,
);
}
/**
* Implements hook_entity_insert().
*/
function farm_livestock_entity_insert($entity, $type) {
// If this is a birth log, sync children.
if ($type == 'log' && $entity->type == 'farm_birth') {
farm_livestock_birth_log_sync($entity);
}
}
/**
* Implements hook_entity_update().
*/
function farm_livestock_entity_update($entity, $type) {
// If this is a birth log, sync children.
if ($type == 'log' && $entity->type == 'farm_birth') {
farm_livestock_birth_log_sync($entity);
}
}
/**
* Sync information in children animals if a birth log is saved.
*
* @param Log $log
* The log entity that is being created or updated.
*/
function farm_livestock_birth_log_sync($log) {
// Load log entity metadata wrapper.
$log_wrapper = entity_metadata_wrapper('log', $log);
// Get the mother animal asset ID from the birth log.
$mother_id = $log_wrapper->field_farm_mother->getIdentifier();
// Iterate through the children assets.
foreach ($log_wrapper->field_farm_asset->getIterator() as $delta => $child_wrapper) {
// We will only save the child asset if we need to.
$save = FALSE;
// If the animal's date of birth does not match the timestamp of the birth
// log, sync it.
if ($child_wrapper->field_farm_date->value() != $log->timestamp) {
$child_wrapper->field_farm_date->set($log->timestamp);
drupal_set_message(t('<a href="!asset_path">@asset_label</a>\'s date of birth has been updated to match their birth log.', array('!asset_path' => 'farm/asset/' . $child_wrapper->getIdentifier(), '@asset_label' => $child_wrapper->label())));
$save = TRUE;
}
// If a mother is specified, make sure that it is listed as one of the
// child's parents.
if (!empty($mother_id)) {
// Iterate through the child's parents to see if the mother is listed.
$mother_exists = FALSE;
foreach ($child_wrapper->field_farm_parent->getIterator() as $delta => $parent_wrapper) {
if ($parent_wrapper->getIdentifier() == $mother_id) {
$mother_exists = TRUE;
}
}
// If the mother is not one of the child's parents, add her.
if (!$mother_exists) {
$child_wrapper->field_farm_parent[] = $mother_id;
$message_args = array(
'!mother_path' => 'farm/asset/' . $log_wrapper->field_farm_mother->getIdentifier(),
'@mother_label' => $log_wrapper->field_farm_mother->label(),
'!child_path' => 'farm/asset/' . $child_wrapper->getIdentifier(),
'@child_label' => $child_wrapper->label(),
);
drupal_set_message(t('<a href="!mother_path">@mother_label</a> was added to <a href="!child_path">@child_label</a>\'s parents.', $message_args));
$save = TRUE;
}
}
// Save the asset, if necessary.
if ($save) {
$child_wrapper->save();
}
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function farm_livestock_form_farm_asset_form_alter(&$form, &$form_state, $form_id) {
// Get the farm asset entity from the form.
$asset = $form['farm_asset']['#value'];
// If the asset is not an animal, bail.
if ($asset->type != 'animal') {
return;
}
// Get the animal's current weight.
$weight = farm_livestock_animal_weight($asset);
// Add a field for setting the animal's current weight.
$form['weight'] = array(
'#type' => 'fieldset',
'#title' => t('Weight'),
'#description' => t('Set the current weight for this animal. If this record is used to represent multiple animals, enter their average weight. An observation log will be created automatically to record the weight.'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 100,
'#tree' => TRUE,
);
$form['weight']['value'] = array(
'#type' => 'textfield',
'#title' => t('Weight'),
'#default_value' => !empty($weight['value']) ? $weight['value'] : '',
'#element_validate' => array('element_validate_number'),
);
$form['weight']['units'] = array(
'#type' => 'textfield',
'#title' => t('Units'),
'#autocomplete_path' => 'taxonomy/autocomplete/field_farm_quantity_units',
'#default_value' => !empty($weight['units']) ? $weight['units'] : '',
);
$form['actions']['submit']['#validate'][] = 'farm_livestock_asset_form_validate';
$form['actions']['submit']['#submit'][] = 'farm_livestock_asset_form_submit';
$form['#group_children']['weight'] = 'group_farm_general';
}
/**
* Validate handler for processing the animal weight field.
*
* @param array $form
* The form array.
* @param array $form_state
* The form state array.
*/
function farm_livestock_asset_form_validate(array $form, array &$form_state) {
// If units are set, but not weight, show an error.
if (empty($form_state['values']['weight']['value']) && !empty($form_state['values']['weight']['units'])) {
form_set_error('weight][value', t('Both weight and units must be specified.'));
}
}
/**
* Submit handler for processing the animal weight field.
*
* @param array $form
* The form array.
* @param array $form_state
* The form state array.
*/
function farm_livestock_asset_form_submit(array $form, array &$form_state) {
// Only proceed if weight has a value.
if (empty($form_state['values']['weight']['value'])) {
return;
}
// Only proceed if the value is not the default value.
if ($form_state['values']['weight']['value'] == $form['weight']['value']['#default_value']) {
return;
}
// If an asset doesn't exist, bail.
if (empty($form_state['values']['farm_asset'])) {
return;
}
// Grab the asset, weight, and units.
$asset = $form_state['values']['farm_asset'];
$weight = $form_state['values']['weight']['value'];
$units = $form_state['values']['weight']['units'];
// Create an observation log to set the weight.
farm_livestock_weight_set($asset, $weight, $units);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function farm_livestock_form_log_form_alter(&$form, &$form_state, $form_id) {
// Only act on the birth log form.
if (!(!empty($form['log']['#value']->type) && $form['log']['#value']->type == 'farm_birth')) {
return;
}
// If this is a new birth log form, display a link to the birth quick form
// for convenience.
if (!empty($form['log']['#value']->is_new)) {
drupal_set_message(t('Tip: Use the <a href="@path">Birth Quick Form</a> to quickly record animal births and create child animal records at the same time.', array('@path' => url('farm/quick/birth'))));
}
// Add validation to make sure that the same child is not referenced in
// multiple birth logs.
$form['#validate'][] = 'farm_livestock_birth_log_form_validate';
}
/**
* Validate handler for the birth log form.
*
* @param array $form
* The form array.
* @param array $form_state
* The form state array.
*/
function farm_livestock_birth_log_form_validate(array $form, array &$form_state) {
// Get the log ID (if available).
$log_id = 0;
if (!empty($form_state['values']['log']->id)) {
$log_id = $form_state['values']['log']->id;
}
// Get the referenced assets.
$asset_ids = array();
if (!empty($form_state['values']['field_farm_asset'][LANGUAGE_NONE])) {
foreach ($form_state['values']['field_farm_asset'][LANGUAGE_NONE] as $asset_reference) {
if (empty($asset_reference['target_id'])) {
continue;
}
$asset_ids[] = $asset_reference['target_id'];
}
}
// Perform an entity field query to see if any birth logs already reference
// the assets.
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'log')
->entityCondition('bundle', 'farm_birth')
->propertyCondition('id', $log_id, '!=')
->fieldCondition('field_farm_asset', 'target_id', $asset_ids);
$result = $query->execute();
if (isset($result['log'])) {
$log_ids = array_keys($result['log']);
$logs = entity_load('log', $log_ids);
}
// If matching logs were found, set form error(s).
if (!empty($logs)) {
foreach ($logs as $log) {
$log_label = entity_label('log', $log);
$log_uri = entity_uri('log', $log);
form_set_error('field_farm_asset', t('The existing birth log <a href="@log_path">%log_name</a> already references one or more of the children. More than one birth log cannot reference the same child.', array('%child_name' => '', '@log_path' => url($log_uri['path']), '%log_name' => $log_label)));
}
}
}
/**
* Implements hook_action_info().
*/
function farm_livestock_action_info() {
return array(
'farm_livestock_weight_action' => array(
'type' => 'farm_asset',
'label' => t('Weight'),
'configurable' => TRUE,
'triggers' => array('any'),
'aggregate' => TRUE,
),
);
}
/**
* Configuration form for farm_livestock_weight_action.
*
* @param array $context
* The context passed into the action form function.
* @param array $form_state
* The form state passed into the action form function.
*
* @return array
* Returns a form array.
*/
function farm_livestock_weight_action_form(array $context, array $form_state) {
// Date field.
$form['date'] = array(
'#type' => 'date_select',
'#title' => t('Date'),
'#date_format' => 'M j Y',
'#date_type' => DATE_FORMAT_UNIX,
'#date_year_range' => '-10:+3',
'#default_value' => date('Y-m-d H:i', REQUEST_TIME),
'#required' => TRUE,
);
// Weight.
$form['weight'] = array(
'#type' => 'textfield',
'#title' => t('Weight'),
'#element_validate' => array('element_validate_number'),
'#required' => TRUE,
);
// Units.
$form['units'] = array(
'#type' => 'textfield',
'#title' => t('Units'),
'#autocomplete_path' => 'taxonomy/autocomplete/field_farm_quantity_units',
'#required' => TRUE,
);
// Return the form.
return $form;
}
/**
* Submit handler for farm_livestock_weight_action configuration form.
*
* @param array $form
* The form array.
* @param array $form_state
* The form state array.
*
* @return array
* Returns an array that will end up in the action's context.
*/
function farm_livestock_weight_action_submit(array $form, array $form_state) {
// Start to build the context array.
$context = array();
// Convert the date to a timestamp.
$timestamp = strtotime($form_state['values']['date']);
// The action form only includes month, day, and year. If the measurement is
// today, then we assume that the current time should also be included.
if (date('Ymd', $timestamp) == date('Ymd', REQUEST_TIME)) {
$context['timestamp'] = REQUEST_TIME;
}
// Otherwise, the measurement is in the past/future, so don't include a time.
else {
$context['timestamp'] = $timestamp;
}
// Add the weight and units fields.
$context['weight'] = $form_state['values']['weight'];
$context['units'] = $form_state['values']['units'];
// Return the context array.
return $context;
}
/**
* Action function for farm_livestock_weight_action.
*
* Creates a new weight observation log for the specified assets.
*
* @param array $assets
* An array of asset entities.
* @param array $context
* Array with parameters for this action.
*/
function farm_livestock_weight_action(array $assets, $context = array()) {
// If we're missing assets, weight, units, or a timestamp, bail.
if (empty($assets) || empty($context['weight']) || empty($context['units']) || empty($context['timestamp'])) {
drupal_set_message('Could not set weights because required information was missing.', 'error');
return;
}
// Set the animal weights.
farm_livestock_weight_set($assets, $context['weight'], $context['units'], $context['timestamp']);
}
/**
* Helper function for retrieving the weight of an animal.
*
* @param FarmAsset $asset
* The animal asset to get weight for.
*
* @return array
* Returns an array of quantity information about the asset's weight, based
* on its latest weight quantity log. Returns an empty array if nothing is
* found.
*/
function farm_livestock_animal_weight($asset) {
// Load the latest log with a 'weight' quantity measurement for this asset.
$log = farm_quantity_log_asset($asset, 'weight');
// if no weight observation log exists for asset
if (empty($log)) {
return array();
}
// Extract quantity data from the log.
$data = farm_quantity_log_data($log, 'weight');
// Iterate through the data and return the first one with a value.
foreach ($data as $quantity) {
if (!empty($quantity['value'])) {
return $quantity;
}
}
// If nothing was returned, return an empty array.
return array();
}
/**
* Create a weight measurement log associated with an animal.
*
2018-04-17 21:16:17 +02:00
* @param array $assets
* The assets to add a weight measurement to.
* @param string $weight
* The animal's current weight.
2017-12-16 16:42:27 +01:00
* @param string $units
* The units of measurement.
* @param int $timestamp
* The timestamp of the measurement. Defaults to the current time.
* @param bool $done
* Boolean indicating whether or not the log should be marked "done".
* Defaults to TRUE.
*
* @return \Log
* Returns the log that was created.
*/
function farm_livestock_weight_set($assets, $weight, $units, $timestamp = REQUEST_TIME, $done = TRUE) {
// The log will be an observation.
$log_type = 'farm_observation';
// Set the name to: "Current weight: [value]".
$log_name = t('Current weight') . ': ' . check_plain($weight) . ' ' . check_plain($units);
// If $assets isn't an array, wrap it.
if (!is_array($assets)) {
$assets = array($assets);
}
// Assemble an array of measurements.
$measurements = array(
array(
'measure' => 'weight',
'value' => $weight,
'units' => $units,
'label' => '',
),
);
// Create a new log entity.
$log = farm_quantity_log_create($log_type, $log_name, $timestamp, $done, $assets, $measurements);
// Return the log.
return $log;
}