You are here

farm_plan.module in farmOS 7

Farm plan - A farm plan entity type.

File

modules/farm/farm_plan/farm_plan.module
View source
<?php

/**
 * @file
 * Farm plan - A farm plan entity type.
 */

// Include Features code.
include_once 'farm_plan.features.inc';

/****************************************************************
 * Drupal hooks
 * **************************************************************/

/**
 * Implements hook_permission().
 */
function farm_plan_permission() {
  $perms = array(
    'administer farm_plan module' => array(
      'title' => t('Administer farm plan module'),
      'description' => t('Gives full access to everything in the farm plan module.'),
      'restrict access' => TRUE,
    ),
    'administer farm_plan types' => array(
      'title' => t('Administer farm plan types'),
      'restrict access' => TRUE,
    ),
    'view farm plans' => array(
      'title' => t('View farm plans'),
      'description' => t('Allows users to view the full list of farm plans.'),
    ),
  );

  // Add permissions for each farm_plan type.
  foreach (farm_plan_types() as $farm_plan_type) {
    $type = $farm_plan_type->type;
    $ops = array(
      'view',
      'edit',
      'delete',
    );
    $scopes = array(
      'any',
      'own',
    );
    $perms += array(
      "create {$type} farm plans" => array(
        'title' => t('Create new %type_name farm plans', array(
          '%type_name' => $farm_plan_type->label,
        )),
      ),
    );
    foreach ($ops as $op) {
      foreach ($scopes as $scope) {
        $perms += array(
          "{$op} {$scope} {$type} farm plans" => array(
            'title' => drupal_ucfirst($op) . ' ' . $scope . ' ' . t('%type_name farm plans', array(
              '%type_name' => $farm_plan_type->label,
            )),
          ),
        );
      }
    }
  }
  return $perms;
}

/**
 * Implements hook_menu().
 */
function farm_plan_menu() {
  $items = array();
  $items['farm/plan/add'] = array(
    'title' => 'Add plan',
    'page callback' => 'farm_plan_add_types_page',
    'access callback' => 'farm_plan_add_access',
    'file' => 'farm_plan.pages.inc',
  );
  foreach (farm_plan_types() as $type => $info) {
    $items['farm/plan/add/' . $type] = array(
      'title' => 'Add ' . $info->label,
      'page callback' => 'farm_plan_add',
      'page arguments' => array(
        3,
      ),
      'access callback' => 'farm_plan_access',
      'access arguments' => array(
        'create',
        3,
      ),
      'file' => 'farm_plan.pages.inc',
    );
  }
  $farm_plan_uri = 'farm/plan/%farm_plan';
  $farm_plan_uri_argument_position = 2;
  $items[$farm_plan_uri] = array(
    'title callback' => 'entity_label',
    'title arguments' => array(
      'farm_plan',
      $farm_plan_uri_argument_position,
    ),
    'page callback' => 'farm_plan_view',
    'page arguments' => array(
      $farm_plan_uri_argument_position,
    ),
    'access callback' => 'farm_plan_access',
    'access arguments' => array(
      'view',
      $farm_plan_uri_argument_position,
    ),
    'file' => 'farm_plan.pages.inc',
  );
  $items[$farm_plan_uri . '/view'] = array(
    'title' => 'Plan',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items[$farm_plan_uri . '/delete'] = array(
    'title' => 'Delete plan',
    'title callback' => 'farm_plan_label',
    'title arguments' => array(
      $farm_plan_uri_argument_position,
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'farm_plan_delete_form',
      $farm_plan_uri_argument_position,
    ),
    'access callback' => 'farm_plan_access',
    'access arguments' => array(
      'update',
      $farm_plan_uri_argument_position,
    ),
    'file' => 'farm_plan.pages.inc',
  );
  $items[$farm_plan_uri . '/edit'] = array(
    'title' => 'Settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'farm_plan_form',
      $farm_plan_uri_argument_position,
    ),
    'access callback' => 'farm_plan_access',
    'access arguments' => array(
      'update',
      $farm_plan_uri_argument_position,
    ),
    'file' => 'farm_plan.pages.inc',
    'type' => MENU_LOCAL_TASK,
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
    'weight' => 100,
  );

  // Form for removing a record from a plan.
  // This is the same as the form for deleting records (below), but it will not
  // delete records. It will only unlink them from the plan.
  $items[$farm_plan_uri . '/%/%/remove'] = array(
    'title' => 'Remove record',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'farm_plan_record_remove_form',
      $farm_plan_uri_argument_position,
      3,
      4,
    ),
    'access callback' => 'farm_plan_access',
    'access arguments' => array(
      'update',
      $farm_plan_uri_argument_position,
    ),
    'file' => 'farm_plan.pages.inc',
    'type' => MENU_CALLBACK,
  );

  // Form for deleting a record from a plan.
  // This is the same as the form for removing records (above), but it also
  // gives the option to delete the record.
  $items[$farm_plan_uri . '/%/%/delete'] = array(
    'title' => 'Remove record',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'farm_plan_record_delete_form',
      $farm_plan_uri_argument_position,
      3,
      4,
    ),
    'access callback' => 'farm_plan_access',
    'access arguments' => array(
      'update',
      $farm_plan_uri_argument_position,
    ),
    'file' => 'farm_plan.pages.inc',
    'type' => MENU_CALLBACK,
  );

  // Plan type delete form.
  $items['admin/config/farm/plan-types/%farm_plan_type/delete'] = array(
    'title' => 'Delete',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'farm_plan_type_form_delete_confirm',
      4,
    ),
    'access arguments' => array(
      'administer farm_plan types',
    ),
    'weight' => 1,
    'type' => MENU_NORMAL_ITEM,
    'file' => 'farm_plan.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_entity_info().
 */
function farm_plan_entity_info() {
  $return = array(
    'farm_plan' => array(
      'label' => t('Farm plan'),
      'entity class' => 'FarmPlan',
      'controller class' => 'FarmPlanController',
      'base table' => 'farm_plan',
      'fieldable' => TRUE,
      'entity keys' => array(
        'id' => 'id',
        'bundle' => 'type',
        'label' => 'name',
      ),
      'bundle keys' => array(
        'bundle' => 'type',
      ),
      'bundles' => array(),
      'load hook' => 'farm_plan_load',
      'view modes' => array(
        'full' => array(
          'label' => t('Default'),
          'custom settings' => FALSE,
        ),
      ),
      'label callback' => 'entity_class_label',
      'uri callback' => 'entity_class_uri',
      'module' => 'farm_plan',
      'access callback' => 'farm_plan_access',
    ),
  );
  $return['farm_plan_type'] = array(
    'label' => t('Farm plan type'),
    'entity class' => 'FarmPlanType',
    'controller class' => 'FarmPlanTypeController',
    'base table' => 'farm_plan_type',
    'fieldable' => FALSE,
    'bundle of' => 'farm_plan',
    'exportable' => TRUE,
    'entity keys' => array(
      'id' => 'id',
      'name' => 'type',
      'label' => 'label',
    ),
    'module' => 'farm_plan',
    // Enable the entity API admin UI.
    'admin ui' => array(
      'path' => 'admin/config/farm/plan-types',
      'file' => 'farm_plan.admin.inc',
      'controller class' => 'FarmPlanTypeUIController',
    ),
    'access callback' => 'farm_plan_type_access',
  );
  return $return;
}

/**
 * Implements hook_entity_info_alter().
 */
function farm_plan_entity_info_alter(&$entity_info) {
  foreach (farm_plan_types() as $type => $info) {
    $entity_info['farm_plan']['bundles'][$type] = array(
      'label' => $info->label,
      'admin' => array(
        'path' => 'admin/config/farm/plan-types/manage/%farm_plan_type',
        'real path' => 'admin/config/farm/plan-types/manage/' . $type,
        'bundle argument' => 5,
      ),
    );
  }
}

/**
 * Implements hook_entity_property_info_alter().
 */
function farm_plan_entity_property_info_alter(&$info) {
  $properties =& $info['farm_plan']['properties'];
  $properties['name'] = array(
    'label' => t('Name'),
    'description' => t('The name of the plan.'),
    'setter callback' => 'entity_property_verbatim_set',
    'schema field' => 'name',
  );
  $properties['type'] = array(
    'label' => t('Farm plan type'),
    'type' => 'token',
    'description' => t('The farm plan type.'),
    'setter callback' => 'entity_property_verbatim_set',
    'access callback' => 'farm_plan_properties_access',
    'options list' => 'farm_plan_type_get_names',
    'required' => TRUE,
    'schema field' => 'type',
  );
  $properties['uid'] = array(
    'label' => t('Owner'),
    'type' => 'user',
    'description' => t('The owner of the plan.'),
    'setter callback' => 'entity_property_verbatim_set',
    'access callback' => 'farm_plan_properties_access',
    'required' => TRUE,
    'schema field' => 'uid',
  );
  $properties['created'] = array(
    'label' => t('Created'),
    'type' => 'date',
    'description' => t('The timestamp when the plan was created.'),
    'setter callback' => 'entity_property_verbatim_set',
    'access callback' => 'farm_plan_properties_access',
    'required' => TRUE,
    'schema field' => 'created',
  );
  $properties['changed'] = array(
    'label' => t('Changed'),
    'type' => 'date',
    'description' => t('The timestamp when the plan was last modified.'),
    'setter callback' => 'entity_property_verbatim_set',
    'access callback' => 'farm_plan_properties_access',
    'required' => TRUE,
    'schema field' => 'changed',
  );
  $properties['active'] = array(
    'label' => t('Active'),
    'description' => t('Whether the plan is active.'),
    'setter callback' => 'entity_property_verbatim_set',
    'access callback' => 'farm_plan_properties_access',
    'schema field' => 'active',
    'type' => 'boolean',
  );
}

/**
 * Implements hook_field_extra_fields().
 */
function farm_plan_field_extra_fields() {
  $farm_plan_types = farm_plan_types();
  $extra_fields = array(
    'farm_plan' => array(),
  );
  foreach ($farm_plan_types as $type) {
    $extra_fields['farm_plan'][$type->type] = array(
      'form' => array(
        // Add plan name field to field UI.
        'name' => array(
          'label' => t('Name'),
          'description' => t('The name of the plan.'),
          'weight' => -10,
        ),
      ),
    );
  }
  return $extra_fields;
}

/**
 * Implements hook_entity_view().
 */
function farm_plan_entity_view($entity, $type, $view_mode, $langcode) {

  // If the entity is not a farm_plan, bail.
  if ($type != 'farm_plan') {
    return;
  }

  // Add the plan type.
  $plan_types = farm_plan_type_get_names();
  if (!empty($plan_types[$entity->type])) {
    $entity->content['type'] = array(
      '#markup' => '<div><strong>Plan type:</strong> ' . $plan_types[$entity->type] . '</div>',
      '#weight' => -101,
    );
  }

  // Add the plan's "active" status.
  if ($entity->active) {
    $status = 'Yes';
  }
  else {
    $status = 'No';
    drupal_set_message(t('This plan is no longer active. Inactive plans should be considered "archived" and should not be edited or deleted unless they contain information that is incorrect.'), 'warning');
  }
  $entity->content['active'] = array(
    '#markup' => '<div><strong>Active plan:</strong> ' . $status . '</div>',
    '#weight' => -100,
  );

  // Summarize areas and assets associated with the plan (logs will be added via
  // Views in hook_farm_ui_entity_views() below.
  $plan_areas = farm_plan_linked_records('area', $entity->id);
  if (!empty($plan_areas)) {
    $plan_area_links = array();
    foreach ($plan_areas as $area_id) {
      $area = taxonomy_term_load($area_id);
      $entity_label = entity_label('taxonomy_term', $area);
      $entity_uri = entity_uri('taxonomy_term', $area);
      $plan_area_links[] = l($entity_label, $entity_uri['path']);
    }
    $entity->content['farm_plan_areas'] = array(
      '#markup' => '<div><strong>Areas:</strong> ' . implode(', ', $plan_area_links) . '</div>',
    );
  }
  $plan_assets = farm_plan_linked_records('asset', $entity->id);
  if (!empty($plan_assets)) {
    $plan_asset_links = array();
    foreach ($plan_assets as $asset_id) {
      $asset = farm_asset_load($asset_id);
      $entity_label = entity_label('farm_asset', $asset);
      $entity_uri = entity_uri('farm_asset', $asset);
      $plan_asset_links[] = l($entity_label, $entity_uri['path']);
    }
    $entity->content['farm_plan_assets'] = array(
      '#markup' => '<div><strong>Assets:</strong> ' . implode(', ', $plan_asset_links) . '</div>',
    );
  }
}

/**
 * Implements hook_farm_ui_entity_views().
 */
function farm_plan_farm_ui_entity_views($entity_type, $bundle, $entity) {

  // If the entity is not a plan, bail.
  if (!($entity_type == 'farm_plan')) {
    return array();
  }

  // Display a View of logs associated with the plan.
  return array(
    'farm_plan_logs',
  );
}

/***************************************************************
 * Access functions
 * *************************************************************/

/**
 * Access callback for plan entities.
 *
 * @param string $op
 *   The operation being performed. One of 'view', 'update', 'create', 'delete'.
 * @param FarmPlan|string $farm_plan
 *   Optionally a specific plan entity to check.
 * @param object $account
 *   The user to check for. Leave it to NULL to check for the global user.
 *
 * @return bool
 *   Whether access is allowed or not.
 */
function farm_plan_access($op, $farm_plan = NULL, $account = NULL) {
  $rights =& drupal_static(__FUNCTION__, array());

  // If $op is not one of the supported ones, deny access.
  if (!in_array($op, array(
    'create',
    'view',
    'update',
    'delete',
  ), TRUE)) {
    return FALSE;
  }

  // If no user object is supplied, the access check is for the current user.
  if (empty($account)) {
    global $user;
    $account = $user;
  }

  // If no plan is provided, check for access to all plans.
  if (empty($farm_plan)) {
    return user_access('view farm plans', $account);
  }

  // $farm_plan may be either an object or a plan type. Since plan types
  // cannot be an integer, use either id or type as the static cache id.
  $cid = is_object($farm_plan) ? $farm_plan->id : $farm_plan;

  // If we've already checked access for this plan, user and op, return from
  // cache.
  if (isset($rights[$account->uid][$cid][$op])) {
    return $rights[$account->uid][$cid][$op];
  }

  // If the user has 'administer farm_plan module' permission, grant them
  // access.
  if (user_access('administer farm_plan module', $account)) {
    $rights[$account->uid][$cid][$op] = TRUE;
    return TRUE;
  }

  // Check access to the plan based on it's type.
  $type = is_string($farm_plan) ? $farm_plan : $farm_plan->type;
  $farm_plan_types = farm_plan_types();
  $type_names = array();
  foreach ($farm_plan_types as $name => $farm_plan_type) {
    $type_names[] = $name;
  }
  if (in_array($type, $type_names)) {
    if ($op == 'create' && user_access('create ' . $type . ' farm plans', $account)) {
      $rights[$account->uid][$cid][$op] = TRUE;
      return TRUE;
    }
    if ($op == 'view') {
      if (user_access('view any ' . $type . ' farm plans', $account) || user_access('view own ' . $type . ' farm plans', $account) && $account->uid == $farm_plan->uid) {
        $rights[$account->uid][$cid][$op] = TRUE;
        return TRUE;
      }
    }
    if ($op == 'update') {
      if (user_access('edit any ' . $type . ' farm plans', $account) || user_access('edit own ' . $type . ' farm plans', $account) && $account->uid == $farm_plan->uid) {
        $rights[$account->uid][$cid][$op] = TRUE;
        return TRUE;
      }
    }
    if ($op == 'delete') {
      if (user_access('delete any ' . $type . ' farm plans', $account) || user_access('delete own ' . $type . ' farm plans', $account) && $account->uid == $farm_plan->uid) {
        $rights[$account->uid][$cid][$op] = TRUE;
        return TRUE;
      }
    }
  }

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

/**
 * Access callback: Checks whether the user has permission to add a plan.
 *
 * @param object|null $account
 *   The user account.
 *
 * @return bool
 *   TRUE if the user has add permission, otherwise FALSE.
 */
function farm_plan_add_access($account = NULL) {

  // If no user object is supplied, the access check is for the current user.
  if (empty($account)) {
    global $user;
    $account = $user;
  }

  // Check each of the plan types to see if the user has access.
  $types = farm_plan_types();
  foreach ($types as $type) {
    if (farm_plan_access('create', $type->type, $account)) {
      return TRUE;
    }
  }

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

/**
 * Access callback for plan types.
 *
 * @param string $op
 *   The operation being performed.
 * @param FarmPlanType $farm_plan_type
 *   The farm plan entity.
 *
 * @return bool
 *   Returns true if the user has access.
 */
function farm_plan_type_access($op, FarmPlanType $farm_plan_type = NULL) {
  return user_access('administer farm_plan types');
}

/**
 * Access callback for farm_plan properties.
 */
function farm_plan_properties_access($op, $property, $entity = NULL, $account = NULL) {

  // Delegate to the general farm_plan access callback, based on the $op.
  switch ($op) {
    case 'view':
      return farm_plan_access('view', $entity, $account);
    case 'edit':
      return farm_plan_access('update', $entity, $account);
  }

  // Otherwise, deny access.
  return FALSE;
}

/***************************************************************
 * Farm plan API functions
 * *************************************************************/

/**
 * Load a plan.
 *
 * @param int $id
 *   The plan id.
 * @param bool $reset
 *   Whether or not to reset the entity cache.
 *
 * @return FarmPlan
 *   Returns a farm plan object.
 */
function farm_plan_load($id, $reset = FALSE) {
  $farm_plans = farm_plan_load_multiple(array(
    $id,
  ), array(), $reset);
  return reset($farm_plans);
}

/**
 * Load multiple plans based on certain conditions.
 *
 * @param array $ids
 *   An array of farm plan ids.
 * @param array $conditions
 *   An array of entity load conditions.
 * @param bool $reset
 *   Whether or not to reset the entity cache.
 *
 * @return array
 *   Returns an array of farm plans.
 */
function farm_plan_load_multiple($ids = array(), $conditions = array(), $reset = FALSE) {
  return entity_load('farm_plan', $ids, $conditions, $reset);
}

/**
 * Save plan.
 *
 * @param FarmPlan $farm_plan
 *   The farm plan entity.
 */
function farm_plan_save(FarmPlan $farm_plan) {
  entity_save('farm_plan', $farm_plan);
}

/**
 * Delete single plan.
 *
 * @param FarmPlan $farm_plan
 *   The farm plan entity.
 */
function farm_plan_delete(FarmPlan $farm_plan) {
  entity_delete('farm_plan', entity_id('farm_plan', $farm_plan));
}

/**
 * Delete multiple plans.
 *
 * @param array $farm_plan_ids
 *   An array of farm plan ids.
 */
function farm_plan_delete_multiple(array $farm_plan_ids) {
  entity_delete_multiple('farm_plan', $farm_plan_ids);
}

/***************************************************************
 * Farm plan type API functions
 * *************************************************************/

/**
 * Load plan type.
 *
 * @param string $farm_plan_type
 *   The farm plan type.
 *
 * @return FarmPlanType
 *   Returns a farm plan type entity.
 */
function farm_plan_type_load($farm_plan_type) {
  return farm_plan_types($farm_plan_type);
}

/**
 * List of plan types.
 *
 * @param string $type_name
 *   The farm plan type name.
 *
 * @return FarmPlanType|array
 *   Returns either a single type, or an array of types.
 */
function farm_plan_types($type_name = NULL) {
  $types = entity_load_multiple_by_name('farm_plan_type', isset($type_name) ? array(
    $type_name,
  ) : FALSE);
  return isset($type_name) ? reset($types) : $types;
}

/**
 * Save plan type entity.
 *
 * @param FarmPlanType $farm_plan_type
 *   The farm plan type entity.
 */
function farm_plan_type_save(FarmPlanType $farm_plan_type) {
  entity_save('farm_plan_type', $farm_plan_type);
}

/**
 * Delete single plan type.
 *
 * @param FarmPlanType $farm_plan_type
 *   The farm plan type entity.
 */
function farm_plan_type_delete(FarmPlanType $farm_plan_type) {
  entity_delete('farm_plan_type', entity_id('farm_plan_type', $farm_plan_type));
}

/**
 * Delete multiple plan types.
 *
 * @param array $farm_plan_type_ids
 *   An array of farm plan type ids.
 */
function farm_plan_type_delete_multiple(array $farm_plan_type_ids) {
  entity_delete_multiple('farm_plan_type', $farm_plan_type_ids);
}

/**
 * Get the names of all plan types.
 *
 * @return array
 *   Returns an array of plan type names, keyed by machine name.
 */
function farm_plan_type_get_names() {
  $names = array();
  $types = farm_plan_types();
  foreach ($types as $type) {
    $names[$type->type] = $type->label;
  }
  return $names;
}

/***************************************************************
 * Functions for linking/unlinking plans with other records.
 * *************************************************************/

/**
 * Load a list of records associated with a plan.
 *
 * @param string $record_type
 *   The record type (see farm_plan_record_relationships()).
 * @param int $plan_id
 *   The plan ID.
 *
 * @return array
 *   Returns an array of record IDs associated with the plan ID.
 */
function farm_plan_linked_records($record_type, $plan_id) {

  // Start an empty records array.
  $records = array();

  // If the plan ID is empty, bail.
  if (empty($plan_id)) {
    return;
  }

  // Get available relationships between plans and other record types.
  $relationships = farm_plan_record_relationships();

  // If a database table and field are not available, bail.
  if (empty($relationships[$record_type]['table']) || empty($relationships[$record_type]['field'])) {
    return;
  }

  // Get the table and field.
  $table = $relationships[$record_type]['table'];
  $field = $relationships[$record_type]['field'];

  // Query for record IDs.
  $query = db_select($table, 'r');
  $query
    ->addField('r', $field);
  $query
    ->condition('plan_id', $plan_id);
  $result = $query
    ->execute();
  foreach ($result as $row) {
    if (!empty($row->{$field})) {
      $records[] = $row->{$field};
    }
  }

  // Return the record IDs.
  return $records;
}

/**
 * Link a plan to a record.
 *
 * @param string $record_type
 *   The record type (see farm_plan_record_relationships()).
 * @param int $plan_id
 *   The plan ID.
 * @param int $record_id
 *   The record ID.
 * @param array $primary_record
 *   If this is not the primary/required record type in the table, the primary
 *   record key/value to needed for updating the existing record.
 *   For example: array('asset_id' => 5)
 */
function farm_plan_link_record($record_type, $plan_id, $record_id, $primary_record = array()) {

  // First, delete any existing link.
  farm_plan_unlink_record($record_type, $plan_id, $record_id);

  // Get available relationships between plans and other record types.
  $relationships = farm_plan_record_relationships();

  // If a database table and field are not available, bail.
  if (empty($relationships[$record_type]['table']) || empty($relationships[$record_type]['field'])) {
    return;
  }

  // Get the table and field.
  $table = $relationships[$record_type]['table'];
  $field = $relationships[$record_type]['field'];

  // If this record type is not required, and a primary key/value is provided,
  // then update the existing relationship row.
  if ($relationships[$record_type]['required'] === FALSE && !empty($primary_record)) {
    $primary_record_key = key($primary_record);
    $primary_record_id = current($primary_record);
    $record = array(
      'plan_id' => $plan_id,
      $primary_record_key => $primary_record_id,
      $field => $record_id,
    );
    $primary_keys = array(
      'plan_id',
      $primary_record_key,
    );
    drupal_write_record($table, $record, $primary_keys);
  }
  else {
    $record = array(
      'plan_id' => $plan_id,
      $field => $record_id,
    );
    drupal_write_record($table, $record);
  }
}

/**
 * Unlink a plan from an area.
 *
 * @param string $record_type
 *   The record type (see farm_plan_record_relationships()).
 * @param int $plan_id
 *   The plan ID.
 * @param int $record_id
 *   The record ID.
 */
function farm_plan_unlink_record($record_type, $plan_id, $record_id) {

  // Get available relationships between plans and other record types.
  $relationships = farm_plan_record_relationships();

  // If a database table and field are not available, bail.
  if (empty($relationships[$record_type]['table']) || empty($relationships[$record_type]['field'])) {
    return;
  }

  // Get the table and field.
  $table = $relationships[$record_type]['table'];
  $field = $relationships[$record_type]['field'];

  // If this record type is not required, simply update the relationship row in
  // the database to remove reference to the record.
  if ($relationships[$record_type]['required'] === FALSE) {
    $query = db_update($table);
    $query
      ->fields(array(
      $field => NULL,
    ));
    $query
      ->condition('plan_id', $plan_id);
    $query
      ->condition($field, $record_id);
    $query
      ->execute();
  }
  else {
    $query = db_delete($table);
    $query
      ->condition('plan_id', $plan_id);
    $query
      ->condition($field, $record_id);
    $query
      ->execute();
  }
}

/**
 * Defines available relationships between plans and other record types.
 *
 * @return array
 *   Returns an array of record types with the database table and field names
 *   used to store relationships. See farm_plan.api.php.
 */
function farm_plan_record_relationships() {

  // Ask modules for relationships.
  $relationships = module_invoke_all('farm_plan_record_relationships');

  // Set default values.
  foreach ($relationships as &$relationship) {
    if (!isset($relationship['required'])) {
      $relationship['required'] = TRUE;
    }
  }

  // Return the relationships.
  return $relationships;
}

/**
 * Implements hook_farm_plan_record_relationships().
 */
function farm_plan_farm_plan_record_relationships() {
  return array(
    'area' => array(
      'label' => t('Area'),
      'entity_type' => 'taxonomy_term',
      'entity_type_table' => 'taxonomy_term_data',
      'entity_pk' => 'tid',
      'table' => 'farm_plan_area',
      'field' => 'area_id',
    ),
    'asset' => array(
      'label' => t('Asset'),
      'entity_type' => 'farm_asset',
      'entity_pk' => 'id',
      'table' => 'farm_plan_asset',
      'field' => 'asset_id',
    ),
    'log' => array(
      'label' => t('Log'),
      'entity_type' => 'log',
      'entity_pk' => 'id',
      'table' => 'farm_plan_log',
      'field' => 'log_id',
    ),
    'user' => array(
      'label' => t('User'),
      'entity_type' => 'user',
      'entity_pk' => 'uid',
      'table' => 'farm_plan_user',
      'field' => 'user_id',
    ),
  );
}

/**
 * Implements hook_entity_view_alter().
 */
function farm_plan_entity_view_alter(&$build, $type) {

  // Get the entity ID. Bail if not found.
  $entity_id = NULL;
  if (!empty($build['#entity'])) {
    $entity_id = entity_id($type, $build['#entity']);
  }
  elseif (!empty($build['#term'])) {
    $entity_id = entity_id($type, $build['#term']);
  }
  if (empty($entity_id)) {
    return;
  }

  // Get available relationships between plans and other record types.
  $relationships = farm_plan_record_relationships();

  // Iterate through the relationships to find a matching record type.
  $record_type = '';
  foreach ($relationships as $relationship => $info) {
    if ($type == $info['entity_type']) {
      $record_type = $relationship;
      break;
    }
  }

  // If a record type wasn't found, bail.
  if (empty($record_type)) {
    return;
  }

  // Find plan(s) that this entity is associated with.
  $query = 'SELECT plan_id FROM {' . $relationships[$record_type]['table'] . '} WHERE ' . $relationships[$record_type]['field'] . ' = :entity_id';
  $args = array(
    ':entity_id' => $entity_id,
  );
  $result = db_query($query, $args);
  $plan_ids = array();
  foreach ($result as $row) {
    if (!empty($row->plan_id)) {
      $plan_ids[] = $row->plan_id;
    }
  }

  // Iterate through the plans.
  foreach ($plan_ids as $plan_id) {

    // Load the plan.
    $plan = farm_plan_load($plan_id);

    // Get the plan URL and name.
    $plan_uri = entity_uri('farm_plan', $plan);
    $plan_path = $plan_uri['path'];
    $plan_name = entity_label('farm_plan', $plan);

    // Set a message pointing to the plan.
    $args = array(
      '@record_type' => $relationships[$record_type]['label'],
      '!plan_path' => url($plan_path),
      '%plan_name' => $plan_name,
    );
    $message = t('This @record_type is part of the plan: <a href="!plan_path">%plan_name</a>', $args);
    drupal_set_message($message);
  }
}

/**
 * Implements hook_entity_update().
 */
function farm_plan_entity_update($entity, $type) {

  // If a plan is made inactive, archive all assets linked to it, and vice
  // versa.
  if ($type != 'farm_plan') {
    return;
  }
  if (!(isset($entity->original) && isset($entity->original->active))) {
    return;
  }
  if ($entity->active == $entity->original->active) {
    return;
  }
  if (empty($entity->active)) {
    $archived = REQUEST_TIME;
  }
  else {
    $archived = FALSE;
  }
  $asset_ids = farm_plan_linked_records('asset', $entity->id);
  foreach ($asset_ids as $asset_id) {
    $asset = farm_asset_load($asset_id);
    if ($asset->archived != $archived) {
      $asset->archived = $archived;
      farm_asset_save($asset);

      // If the asset was archived, set a message.
      if (!empty($archived)) {
        $asset_label = entity_label('farm_asset', $asset);
        $asset_uri = entity_uri('farm_asset', $asset);
        $message = t('The asset <a href="!asset_path">%asset_label</a> has been archived.', array(
          '!asset_path' => url($asset_uri['path']),
          '%asset_label' => $asset_label,
        ));
        drupal_set_message($message);
      }
    }
  }
}

/**
 * Implements hook_entity_delete().
 */
function farm_plan_entity_delete($entity, $type) {

  // Get the entity ID, and skip if it couldn't be found.
  $entity_id = entity_id($type, $entity);
  if (empty($entity_id)) {
    return;
  }

  // If the entity ID is not numeric, bail.
  if (!is_numeric($entity_id)) {
    return;
  }

  // Get available relationships between plans and other record types.
  $relationships = farm_plan_record_relationships();

  // Make a list of relationships indexed by entity type.
  $entity_types = array();
  foreach ($relationships as $relationship => $info) {
    if (!empty($info['entity_type'])) {
      $entity_types[$info['entity_type']][] = $relationship;
    }
  }

  // If a related entity type is being deleted, delete any references to that
  // entity in the relationship table.
  // In theory, this shouldn't happen because farm_constraint prevents entities
  // from being deleted that are linked to plans. But, it could still happen via
  // an uninformed call to entity_delete(), so we have this logic here to
  // handle cleanup regardless.
  if (array_key_exists($type, $entity_types)) {
    foreach ($entity_types[$type] as $relationship) {

      // Get information about the relationship.
      $info = $relationships[$relationship];

      // If it doesn't have a table, or a field, skip it.
      if (empty($info['table']) || empty($info['field'])) {
        continue;
      }

      // Delete all references to this plan in the table.
      db_query('DELETE FROM {' . $info['table'] . '} WHERE ' . $info['field'] . ' = :entity_id', array(
        ':entity_id' => $entity_id,
      ));
    }
  }
  elseif ($type == 'farm_plan') {
    foreach ($relationships as $relationship => $info) {

      // If it doesn't have a table, skip it.
      if (empty($info['table'])) {
        continue;
      }

      // Delete all references to this plan in the table.
      db_query('DELETE FROM {' . $info['table'] . '} WHERE plan_id = :plan_id', array(
        ':plan_id' => $entity_id,
      ));
    }
  }
}

Functions

Namesort descending Description
farm_plan_access Access callback for plan entities.
farm_plan_add_access Access callback: Checks whether the user has permission to add a plan.
farm_plan_delete Delete single plan.
farm_plan_delete_multiple Delete multiple plans.
farm_plan_entity_delete Implements hook_entity_delete().
farm_plan_entity_info Implements hook_entity_info().
farm_plan_entity_info_alter Implements hook_entity_info_alter().
farm_plan_entity_property_info_alter Implements hook_entity_property_info_alter().
farm_plan_entity_update Implements hook_entity_update().
farm_plan_entity_view Implements hook_entity_view().
farm_plan_entity_view_alter Implements hook_entity_view_alter().
farm_plan_farm_plan_record_relationships Implements hook_farm_plan_record_relationships().
farm_plan_farm_ui_entity_views Implements hook_farm_ui_entity_views().
farm_plan_field_extra_fields Implements hook_field_extra_fields().
farm_plan_linked_records Load a list of records associated with a plan.
farm_plan_link_record Link a plan to a record.
farm_plan_load Load a plan.
farm_plan_load_multiple Load multiple plans based on certain conditions.
farm_plan_menu Implements hook_menu().
farm_plan_permission Implements hook_permission().
farm_plan_properties_access Access callback for farm_plan properties.
farm_plan_record_relationships Defines available relationships between plans and other record types.
farm_plan_save Save plan.
farm_plan_types List of plan types.
farm_plan_type_access Access callback for plan types.
farm_plan_type_delete Delete single plan type.
farm_plan_type_delete_multiple Delete multiple plan types.
farm_plan_type_get_names Get the names of all plan types.
farm_plan_type_load Load plan type.
farm_plan_type_save Save plan type entity.
farm_plan_unlink_record Unlink a plan from an area.