$bundle->term_id)); $term = reset($term); // If it's the term you are interested in then suggest a format. if ($term->name == 'organism') { // To suggest a format, add an element to the array with a format & weight key. $format[] = array( // This is the format/pattern you suggest be used to determine the title of organism pages. 'format' => '[organism__genus] [organism__species]', // The weight/priority of your suggestion. 'weight' => -5 ); } // Say you know that in your particular site, all 'names' are required // and you want to only use the human-readable name: //--------------------------------------------------------------------------- $name_field = preg_grep('/__name]$/', array_keys($available_tokens)); $name_field = reset($name_field); if (is_string($name_field)) { $format[] = array( 'format' => $name_field, 'weight' => -2, ); } return $format; } /** * A replacement for the entity_load function of Drupal. * * This function should be used for loading of Tripal Entities. It provides * greater control to limit which fields are loaded with the entity. The * entity_load() function of Drupal will automatically attach all fields at * once but this may not be desired as some fields can be comples and large and * the site developer may desire loading of fields via AJAX or the user of * web services may wish to specify the fields they want to include. * * @param $entity_type: * The entity type to load, e.g. node or user. * @param $ids * An array of entity IDs, or FALSE to load all entities. * @param $reset: Whether to reset the internal cache for the requested entity * type. Defaults to FALSE. * @param $field_ids * A list of numeric field IDs that should be loaded. The * TripalField named 'content_type' is always automatically added. * * @return * An array of entity objects indexed by their ids. When no results are * found, an empty array is returned. * * @ingroup tripal_entities_api */ function tripal_load_entity($entity_type, $ids = FALSE, $reset = FALSE, $field_ids = array()) { // The $conditions is deprecated in the funtion arguments of entity_load // so it was removed from the parameters of this function as well. But // the load() function of the entity controller still expects it so set it // to an empty array. $conditions = array(); // If this isn't a TripalEntity then just load it the old fashioned way // although caching will not be used if it not specifically set to FALSE. if ($entity_type != 'TripalEntity') { return entity_load($entity_type, $ids, $conditions, $reset); } // Get the entity controller and clear the cache if requested (default). $ec = entity_get_controller($entity_type); if ($reset) { $ec->resetCache(); } return $ec->load($ids, $conditions, $field_ids); } /** * Retrieves a TripalTerm entity that matches the given arguments. * * @param $values * An associative array used to match a term. Valid keys may be 'vocabulary', * 'accession, or 'term_id'. The keys 'vocabulary' and 'accession' must * always be used together to uniquely identify a term. The key 'term_id' * can be used alone to uniquely identify a term. * * @return * A TripalTerm entity object or NULL if not found. * * @ingroup tripal_entities_api */ function tripal_load_term_entity($values) { $vocabulary = array_key_exists('vocabulary', $values) ? $values['vocabulary'] : ''; $accession = array_key_exists('accession', $values) ? $values['accession'] : ''; $term_id = array_key_exists('term_id', $values) ? $values['term_id'] : ''; $term = NULL; if ($vocabulary and $accession) { $query = db_select('tripal_term', 'tt'); $query->join('tripal_vocab', 'tv', 'tv.id = tt.vocab_id'); $query->fields('tt', array('id')) ->fields('tv', array('vocabulary')) ->condition('tv.vocabulary', $vocabulary) ->condition('tt.accession', $accession); $term = $query->execute()->fetchObject(); } else if ($term_id) { $query = db_select('tripal_term', 'tt'); $query->fields('tt', array('id')) ->condition('tt.id', $term_id); $term = $query->execute()->fetchObject(); } if ($term) { $entity = entity_load('TripalTerm', array($term->id)); return reset($entity); } return NULL; } /** * Retrieves a TripalVocab entity that maches the given arguments. * * @param $values * An associative array used to match a vocabulary. The valid keys are * 'vocab_id' and 'vocabulary'. * * @return * A TripalVocab entity object or NULL if not found. * * @ingroup tripal_entities_api */ function tripal_load_vocab_entity($values) { $vocabulary = array_key_exists('vocabulary', $values) ? $values['vocabulary'] : ''; $vocab_id = array_key_exists('vocab_id', $values) ? $values['vocab_id'] : ''; $vocab = NULL; $query= db_select('tripal_vocab', 'tv') ->fields('tv'); if ($vocabulary) { $query->condition('tv.vocabulary', $vocabulary); } if ($vocab_id) { $query->condition('tv.id', $vocab_id); } $vocab = $query->execute()->fetchObject(); if ($vocab) { $entity = entity_load('TripalVocab', array($vocab->id)); return reset($entity); } return NULL; } /** * Retrieves a TripalBundle entity that matches the given arguments. * * @param $values * An associative array used to match a bundle. Valid keys may: * - id: the numeric id of the bundle. * - name: the bundle name (e.g. 'bio_data_234') * - label: the bundle label (e.g. 'Organism') * - term_id: the term ID to which the bundle belongs * * @return * A TripalBundle entity object or NULL if not found. * * @ingroup tripal_entities_api */ function tripal_load_bundle_entity($values) { $query = db_select('tripal_bundle', 'tb'); $query->fields('tb'); if (array_key_exists('id', $values)) { $query->condition('tb.id', $values['id']); } if (array_key_exists('name', $values)) { $query->condition('tb.name', $values['name']); } if (array_key_exists('label', $values)) { $query->condition('tb.label', $values['label']); } if (array_key_exists('term_id', $values)) { $query->condition('tb.term_id', $values['term_id']); } $bundle = $query->execute()->fetchObject(); if ($bundle) { $entity = entity_load_unchanged('TripalBundle', $bundle->id); return $entity; } return NULL; } /** * Allows a module to write to the admin notification table * during the cron run. * * @param $title * A generic phrase indicating what the notification is for. * @param $details * A human-readable sentence or two describing the issue. * @param $type * A one word type indicating the type of notification. Tripal types include: Jobs, Fields. * If not type is required please pass NULL. * @param $actions * A serialized PHP associative array containing the link and URL for each action. * If not type is required please pass NULL. * @param $submitter_id * A unique ID provided by the submitter for checking to make sure that the notification is not added more than once. * * @ingroup tripal_entities_api */ function tripal_add_notification($title, $details, $type, $actions, $submitter_id) { $transaction = db_transaction(); // Check the notification isn't already in the admin notification table. $dedup = db_select('tripal_admin_notfications', 'tan') ->fields('tan') ->condition('submitter_id', $submitter_id, '=') ->execute()->fetchAll(); if (empty($dedup)) { try { $record = new stdClass; $record->details = $details; $record->title = $title; $record->submitter_id = $submitter_id; $record->actions = serialize($actions); $record->enabled = 1; $record->type = $type; $success = drupal_write_record('tripal_admin_notfications', $record); } catch (Exception $e) { $transaction->rollback(); watchdog('tripal_cron', 'Could not write notification to database.'); } } } /** * Creates a new Tripal Entity type (i.e. bundle). * * @param $args * An array of arguments that must include the following keys: * - vocabulary: The abbreviated vocabulary for the vocabulary * (e.g. RO, SO, PATO). * - accession: The unique term ID in the vocabulary $vocabulary * (i.e. an accession). * - term_name: A human-readable name for this term. This will became * the name that appears for the content type. In practice, this * should be the name of the term. (E.g. the name for SO:0000704 is gene). * @param $error * A string, passed by reference, that is filled with the error message * if the function fails. * * @return * The bundle object or FALSE if failure. * * @ingroup tripal_entities_api */ function tripal_create_bundle($args, &$error = '') { $vocabulary = $args['vocabulary']; $accession = $args['accession']; $term_name = $args['term_name']; $storage_args = $args['storage_args']; $transaction = db_transaction(); try { // First create the TripalVocab if it doesn't already exist. $vocab = tripal_load_vocab_entity(array('vocabulary' => $vocabulary)); if (!$vocab) { $vocab = entity_get_controller('TripalVocab')->create(array('vocabulary' => $vocabulary)); $vocab->save(); } // Next create the TripalTerm if it doesn't already exist. $term = tripal_load_term_entity(array( 'vocabulary' => $vocabulary, 'accession' => $accession )); if (!$term) { $targs = array('vocab_id' => $vocab->id, 'accession' => $accession, 'name' => $term_name); $term = entity_get_controller('TripalTerm')->create($targs); $term = $term->save(); } // If the bundle doesn't already exist, then add it. $bundle_name = 'bio_data_' . $term->id; $einfo = entity_get_info('TripalEntity'); if (!in_array($bundle_name, array_keys($einfo['bundles']))) { // Make the label for the content type have capitalized words. The // exception is 'mRNA' which we know should not be uppercased. $label = ucwords(preg_replace('/_/', ' ', $term_name)); if ($term_name == 'mRNA') { $label = $term_name; } // Insert the bundle. db_insert('tripal_bundle') ->fields(array( 'label' => $label, 'type' => 'TripalEntity', 'name' => $bundle_name, 'term_id' => $term->id, )) ->execute(); } $bundle = tripal_load_bundle_entity(array('name' => $bundle_name)); $modules = module_implements('bundle_create'); foreach ($modules as $module) { $function = $module . '_bundle_create'; $function($bundle, $storage_args); } // Clear the entity cache so that Drupal will read our // hook_entity_info() implementation. global $language; $langcode = $language->language; cache_clear_all("entity_info:$langcode", 'cache'); variable_set('menu_rebuild_needed', TRUE); // Get the bundle object. $bundle = tripal_load_bundle_entity(array('name' => $bundle_name)); tripal_create_bundle_fields($bundle, $term); $modules = module_implements('bundle_postcreate'); foreach ($modules as $module) { $function = $module . '_bundle_postcreate'; $function($bundle); } } catch (Exception $e) { $transaction->rollback(); drupal_set_message(t("Failed to create content type: %message.", array('%message' => $e->getMessage())), 'error'); return FALSE; } return $bundle; } /* * Checks access permissions for a given entity. * * This function is set for TripalEntity access checking in the * tripal_entity_info() under the 'access callback' element. * * * @param $entity * The entity to check access for. function tripal_entity_permissions($entity) { if ($entity) { $bundle_name = $entity->bundle; } else { return FALSE; } // Get the bundle object. $bundle = tripal_load_bundle_entity(array('name' => $bundle_name)); // Identify the administrative user roles. $admin_role = user_role_load_by_name('administrator'); $roles = array($admin_role->rid => $admin_role->name); // Define the permissions. $permission_for_role = array( 'create ' . $bundle->label => TRUE, 'view ' . $bundle->label => TRUE, 'edit ' . $bundle->label => TRUE, 'delete ' . $bundle->label => TRUE, ); // Assign the permissions foreach($roles as $role => $value){ user_role_grant_permissions($role, $permission_for_role); watchdog('debug', '
tripal_entity_permissions $role: '. print_r($role, TRUE) .''); } return TRUE; } */ /** * Retrieves a list of the content types. * * @return * An array of bundles. Each bundle is an object containing information * about that bundle. * * @ingroup tripal_entities_api */ function tripal_get_content_types() { return db_select('tripal_bundle', 'tb') ->fields('tb') ->execute() ->fetchAll(); } /** * Refreshes the bundle such that new fields added by modules will be found during cron. * * @param $bundle_name * The name of the bundle to refresh (e.g. bio_data_4). * * @ingroup tripal_entities_api */ function tripal_tripal_cron_notification() { $num_created = 0; // Get all bundle names to cycle through. $all_bundles = db_select('tripal_bundle', 'tb') ->fields('tb', array('name')) ->execute()->fetchAll(); foreach ($all_bundles as $bundle_name){ // Get the bundle object. $bundle = tripal_load_bundle_entity(array('name' => $bundle_name->name)); if (!$bundle) { tripal_report_error('tripal', TRIPAL_ERROR, "Unrecognized bundle name '%bundle'.", array('%bundle' => $bundle_name)); return FALSE; } // Allow modules to add fields to the new bundle. $modules = module_implements('bundle_fields_info'); foreach ($modules as $module) { $function = $module . '_bundle_fields_info'; $info = $function('TripalEntity', $bundle); foreach ($info as $field_name => $details) { // If the field already exists then skip it. $field = field_info_field($details['field_name']); if ($field) { continue; } // Create notification that new fields exist. $detail_info = ' Tripal has detected a new field ' . $details['field_name'] .' for ' . $bundle->label. ' content type is available for import.'; $title = 'New field available for import'; $actions['Import'] = 'admin/import/field/' . $details['field_name'] . '/' . $bundle_name->name . '/' . $module . '/field'; $type = 'Field'; $submitter_id = $details['field_name'] . '-' . $bundle_name->name . '-' . $module; tripal_add_notification($title, $detail_info, $type, $actions, $submitter_id); $num_created++; } } // Allow modules to add instances to the new bundle. $modules = module_implements('bundle_instances_info'); foreach ($modules as $module) { $function = $module . '_bundle_instances_info'; $info = $function('TripalEntity', $bundle); foreach ($info as $field_name => $details) { // If the field is already attached to this bundle then skip it. $field = field_info_field($details['field_name']); if ($field and array_key_exists('bundles', $field) and array_key_exists('TripalEntity', $field['bundles']) and in_array($bundle->name, $field['bundles']['TripalEntity'])) { continue; } // Create notification that new fields exist. $detail_info = ' Tripal has detected a new field ' . $details['field_name'] .' for ' . $bundle->label. ' content type is available for import.'; $title = 'New field available for import'; $actions['Import'] = 'admin/import/field/' . $details['field_name'] . '/' . $bundle->name . '/' . $module . '/instance'; $type = 'Field'; $submitter_id = $details['field_name'] . '-' . $bundle_name->name . '-' . $module; tripal_add_notification($title, $detail_info, $type, $actions, $submitter_id); $num_created++; } } } } /** * Retrieves information about a given content type. * * @param $bundle_name * The name of a bundle. * * @return * An object containing information about the bundle. * * @ingroup tripal_entities_api */ function tripal_get_content_type($bundle_name) { return db_select('tripal_bundle', 'tb') ->fields('tb') ->condition('tb.name', $bundle_name) ->execute() ->fetchAll(); } /** * Refreshes the bundle such that new fields added by modules will be found. * * @param $bundle_name * The name of the bundle to refresh (e.g. bio_data_4). * * @return * The array of field instance names that were added. * * @ingroup tripal_entities_api */ function tripal_create_bundle_fields($bundle, $term) { $added = array(); // Allow modules to add fields to the new bundle. $modules = module_implements('bundle_fields_info'); $info = array(); foreach ($modules as $module) { $function = $module . '_bundle_fields_info'; $temp = $function('TripalEntity', $bundle); $info = array_merge($info, $temp); } // Allow modules to alter which fields should be attached to content // types they create. drupal_alter('bundle_fields_info', $info, $bundle, $term); // Iterate through all of the fields and create them. foreach ($info as $field_name => $details) { $field_type = $details['type']; // TODO: make sure the field term exits. If not then // skip it. // If the field already exists then skip it. $field = field_info_field($details['field_name']); if ($field) { continue; } // Create the field. $field = field_create_field($details); if (!$field) { tripal_set_message(t("Could not create new field: %field.", array('%field' => $details['field_name'])), TRIPAL_ERROR); } } // Allow modules to add instances to the new bundle. $modules = module_implements('bundle_instances_info'); $info = array(); foreach ($modules as $module) { $function = $module . '_bundle_instances_info'; $temp = $function('TripalEntity', $bundle); $info = array_merge($info, $temp); } // Allow modules to alter which fields should be attached to content // types they create. drupal_alter('bundle_instances_info', $info, $bundle, $term); // Iterate through all of the field instances and create them. foreach ($info as $field_name => $details) { // If the field is already attached to this bundle then skip it. $field = field_info_field($details['field_name']); if ($field and array_key_exists('bundles', $field) and array_key_exists('TripalEntity', $field['bundles']) and in_array($bundle->name, $field['bundles']['TripalEntity'])) { continue; } // Create the field instance. $instance = field_create_instance($details); $added[] = $field_name; } return $added; } /** * Updates an existing field and its attached instance to a bundle. * * * @param $field_name * The name of the field. * @param $field_info * An associative array containing the field information. The following * key/value pairs are supported: * 'field_type' : a valid field type. May be any of the Drupal default * fields, one created by the tripal_chado module or another custom module. * 'widget_type' : a valid widget type. May be any of the Drupal default * fields, one created by the tripal_chado module or another custom module. * 'field_settings' : an array of settings that are appropriate for the * selected field type. * 'widget_settings' : an array of settings that are appropriate for the * selected widget type. * 'description' : a default description for this field. * 'label' : a label used as a header for this field. * 'is_required' : indicates if the field is required in the edit form. * 'cardinality' : indicates the number of values this field can support. * the default is 1 (meaning only one value). Use a value of * FIELD_CARDINALITY_UNLIMITED for unlimited number of values. * 'default_value' : A default value for the field. * 'format' : A string indicating the format for the field. Must be * specific to the field. * @param $entity_type_name * The entity type name. * @param $bundle_name * The bundle name. * * @return * FALSE if the field could not be updated * * TODO: this function really shouldn't try to create an instance and * attach to a bundle at the same time. * * @ingroup tripal_entities_api */ function tripal_update_bundle_field($field_name, $field_info, $entity_type_name, $bundle_name) { $field = field_info_field($field_name); // If the field doesn't exists or is not attached to this bundle then // just return, there is nothing left to do. if (!$field or !array_key_exists('bundles', $field) or !array_key_exists($entity_type_name, $field['bundles']) or !in_array($bundle_name, $field['bundles'][$entity_type_name])) { return FALSE; } $field['field_name'] = $field_name; if (array_key_exists('field_type', $field_info)) { $field['cardinality'] = $field_info['cardinality']; } if (array_key_exists('locked', $field_info)) { $field['locked'] = $field_info['locked']; } if (array_key_exists('storage', $field_info)) { $field['storage']['type'] = $field_info['storage']; } if (array_key_exists('field_settings', $field_info)) { $field['settings'] = $field_info['field_settings']; } field_update_field($field); $field_instance['field_name'] = $field_name; $field_instance['entity_type'] = $entity_type_name; $field_instance['bundle'] = $bundle_name; if (array_key_exists('label', $field_info)) { $field['label'] = $field_info['label']; } if (array_key_exists('description', $field_info)) { $field['description'] = $field_info['description']; } if (array_key_exists('widget', $field_info)) { if (array_key_exists('widget_type', $field_info['widget'])) { $field['widget']['type'] = $field_info['widget_type']; } if (array_key_exists('widget_settings', $field_info['widget'])) { $field['widget']['settings'] = $field_info['widget_settings']; } } if (array_key_exists('required', $field_info)) { $field['required'] = $field_info['is_required']; } if (array_key_exists('settings', $field_info)) { $field['settings'] = $field_info['field_settings']; } if (array_key_exists('default_value', $field_info)) { $field['default_value'] = $field_info['default_value']; } if (array_key_exists('format', $field_info)) { $field['format'] = $field_info['format']; } field_update_instance($field_instance); } /** * @section * Bundle Variables. */ /** * Fetch the value for a given tripal variable. * * @param string $variable_name * The name of the variable as in tripal_variables.name. * @param int $bundle_id * The unique identfier for the bundle you want the value for. * @return text * The value of the specified variable for the specified bundle. * * @ingroup tripal_entities_api */ function tripal_get_bundle_variable($variable_name, $bundle_id, $default = FALSE) { $variable = tripal_get_variable($variable_name); // Warn if we can't find the tripal_variable. if (!$variable) { return $default; } // Select the value for this variable. $value = db_select('tripal_bundle_variables', 'var') ->fields('var', array('value')) ->condition('var.bundle_id', $bundle_id) ->condition('var.variable_id', $variable->variable_id) ->execute() ->fetchField(); // Warn if the value appears to be empty. if (!$value) { return $default; } return $value; } /** * Save the value of a tripal variable for a given bundle. * * @param string $variable_name * The name of the variable as in tripal_variables.name. * @param int $bundle_id * The unique identfier for the bundle you want the value for. * @param $text $value * The value of the variable for the given bundle. * * @ingroup tripal_entities_api */ function tripal_set_bundle_variable($variable_name, $bundle_id, $value) { $variable = tripal_get_variable($variable_name); if (!$variable) { if($variable_name === 'hide_empty_field'){ tripal_insert_variable( 'hide_empty_field', 'Structure->Tripal Content Type->edit checkbox to hide empty fields for that bundle.' ); $variable = tripal_get_variable($variable_name); if (!$variable) { return FALSE; } } else { return FALSE; } } // And then we need to write the new format to the tripal_bundle_variables table. $record = array( 'bundle_id' => $bundle_id, 'variable_id' => $variable->variable_id, 'value' => $value, ); // Check whether there is already a format saved. $bundle_variable_id = db_select('tripal_bundle_variables', 'var') ->fields('var', array('bundle_variable_id')) ->condition('var.bundle_id', $record['bundle_id']) ->condition('var.variable_id', $record['variable_id']) ->execute() ->fetchField(); if ($bundle_variable_id) { $record['bundle_variable_id'] = $bundle_variable_id; return drupal_write_record('tripal_bundle_variables', $record, 'bundle_variable_id'); } else { return drupal_write_record('tripal_bundle_variables', $record); } } /** * @section * Title & URL Formats. */ /** * Get Page Title Format for a given Tripal Entity Type. * * @param TripalBundle $bundle * The Entity object for the Tripal Bundle the title format is for. * * @ingroup tripal_entities_api */ function tripal_get_title_format($bundle) { // Get the existing title format if it exists. $title_format = tripal_get_bundle_variable('title_format', $bundle->id); // If there isn't yet a title format for this bundle/type then we should // determine the default. if (!$title_format) { $title_format = tripal_get_default_title_format($bundle); tripal_save_title_format($bundle, $title_format); } return $title_format; } /** * Save Page Title Format for a given Tripal Entity Type. * * @param TripalBundle $entity * The Entity object for the Tripal Bundle the title format is for. * @param string $format * The pattern to be used when generating entity titles for the above type. * * @ingroup tripal_entities_api */ function tripal_save_title_format($entity, $format) { return tripal_set_bundle_variable('title_format', $entity->id, $format); } /** * Determine the default title format to use for an entity. * * @param TripalBundle $bundle * The Entity object for the Tripal Bundle that the title format is for. * * @return string * A default title format. * * @ingroup tripal_entities_api */ function tripal_get_default_title_format($bundle) { $format = ''; // Retrieve all available tokens. $tokens = tripal_get_entity_tokens($bundle); // A) Check to see if more informed modules have suggested a title for this // type. Invoke hook_tripal_default_title_format() to get all suggestions // from other modules. $suggestions = module_invoke_all('tripal_default_title_format', $bundle, $tokens); if ($suggestions) { // Use the suggestion with the lightest weight. $lightest_key = NULL; foreach ($suggestions as $k => $s) { if ($lightest_key === NULL) $lightest_key = $k; if ($s['weight'] < $lightest_key) $lightest_key = $k; } $format = $suggestions[$lightest_key]['format']; return $format; } // B) Generate our own ugly title by simply comma-separating all the // required fields. if (!$format) { $tmp = array(); // Check which tokens are required fields and join them into a default format. foreach($tokens as $token) { if ($token['required']) { $tmp[] = $token['token']; } } $format = implode(', ', $tmp); return $format; } return $format; } /** * Returns an array of tokens based on Tripal Entity Fields. * * @param TripalBundle $entity * The bundle entity for which you want tokens. * @return * An array of tokens where the key is the machine_name of the token. * * @ingroup tripal_entities_api */ function tripal_get_entity_tokens($entity, $options = array()) { $tokens = array(); // Set default options. $options['required only'] = (isset($options['required only'])) ? $options['required only'] : FALSE; $options['include id'] = (isset($options['include id'])) ? $options['include id'] : TRUE; if ($options['include id']) { $token = '[TripalBundle__bundle_id]'; $tokens[$token] = array( 'label' => 'Bundle ID', 'description' => 'The unique identifier for this Tripal Content Type.', 'token' => $token, 'field_name' => NULL, 'required' => TRUE ); $token = '[TripalEntity__entity_id]'; $tokens[$token] = array( 'label' => 'Content/Entity ID', 'description' => 'The unique identifier for an individual piece of Tripal Content.', 'token' => $token, 'field_name' => NULL, 'required' => TRUE ); } $fields = field_info_instances('TripalEntity', $entity->name); foreach ($fields as $f) { // Build the token from the field information. $token = '[' . $f['field_name'] . ']'; $current_token = array( 'label' => $f['label'], 'description' => $f['description'], 'token' => $token, 'field_name' => $f['field_name'], 'required' => $f['required'] ); // If the required only option is set then we only want to add // required fields to the token list. if ($options['required only'] AND $current_token['required']) { $tokens[$token] = $current_token; } // If the required only option is not set then add everything. elseif (!$options['required only']) { $tokens[$token] = $current_token; } } return $tokens; } /** * Replace all Tripal Tokens in a given string. * * NOTE: If there is no value for a token then the token is removed. * * @param string $string * The string containing tokens. * @param TripalEntity $entity * The entity with field values used to find values of tokens. * @param TripalBundle $bundle_entity * The bundle enitity containing special values sometimes needed for token replacement. * * @return * The string will all tokens replaced with values. * * @ingroup tripal_entities_api */ function tripal_replace_entity_tokens($string, &$entity, $bundle_entity = NULL) { // Determine which tokens were used in the format string $used_tokens = array(); if (preg_match_all('/\[\w+\]/', $string, $matches)) { $used_tokens = $matches[0]; } // If there are no tokens then just return the string. if (count($used_tokens) == 0) { return $string; } // If the field are not loaded for the entity then we want to load them // but we won't do a field_attach_load() as that will load all of the // fields. For syncing (publishing) of content loading all fields for // all synced entities causes extreme slowness, so we'll only attach // the necessary fields for replacing tokens. $attach_fields = array(); foreach($used_tokens as $token) { $field_name = str_replace(array('.','[',']'), array('__','',''), $token); if (!property_exists($entity, $field_name)) { $field = field_info_field($field_name); $storage = $field['storage']; $attach_fields[$storage['type']]['storage'] = $storage; $attach_fields[$storage['type']]['fields'][] = $field; } } // If we have any fields that need attaching, then do so now. if (count(array_keys($attach_fields)) > 0) { foreach ($attach_fields as $storage_type => $details) { $storage = $details['storage']; $fields = $details['fields']; $field_ids = array(); foreach ($fields as $field) { $field_ids[$field['id']] = array($entity->id); } $entities = array($entity->id => $entity); } module_invoke($storage['module'], 'field_storage_load', 'TripalEntity', $entities, FIELD_LOAD_CURRENT, $field_ids, array()); } // Now that all necessary fields are attached process the tokens. foreach($used_tokens as $token) { $field_name = str_replace(array('.','[',']'), array('__','',''), $token); $value = ''; if (property_exists($entity, $field_name)) { // Note: there is a memory leak in field_get_items() so we can't use it // here or bulk publishing will slowly erode memory. //$field_value = field_get_items('TripalEntity', $entity, $field_name); if (array_key_exists(0, $entity->{$field_name}['und'])) { $value = $entity->{$field_name}['und'][0]['value']; } // TODO: deal with the value when it is not a scalar. } // The TripalBundle__bundle_id is a special token for substituting the // bundle id. elseif ($field_name === 'TripalBundle__bundle_id') { // Load the bundle entity if we weren't given it. if (!$bundle_entity) { $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle)); } // This token should be the id of the TripalBundle. $value = $bundle_entity->id; } // The TripalBundle__bundle_id is a special token for substituting the // entty id. elseif ($field_name === 'TripalEntity__entity_id') { // This token should be the id of the TripalEntity. $value = $entity->id; } // We can't support tokens that have multiple elements (i.e. in an array). if (is_array($value)) { $string = str_replace($token, '', $string); } else { $string = str_replace($token, $value, $string); } } return $string; } /** * Formats the tokens for display. * * @param array $tokens * A list of tokens generated via tripal_get_entity_tokens(). * @return * Rendered output describing the available tokens. * * @ingroup tripal_entities_api */ function theme_token_list($tokens) { $header = array('Token', 'Name', 'Description'); $rows = array(); foreach ($tokens as $details) { $rows[] = array( $details['token'], $details['label'], $details['description'], ); } return theme('table', array('header' => $header, 'rows' => $rows)); } /** * Define the entity label callback. This will return the title. * * @param $entity * * @return mixed * * @ingroup tripal_entities_api */ function tripal_entity_label($entity) { if (property_exists($entity, 'title')) { return $entity->title; } return NULL; } /** * * @param $bundle_name * * @ingroup tripal_entities_api */ function tripal_get_bundle_details($bundle_name) { global $user; $bundle = tripal_load_bundle_entity(array('name' => $bundle_name)); $term = tripal_load_term_entity(array('term_id' => $bundle->term_id)); $vocab = $term->vocab; $instances = field_info_instances('TripalEntity', $bundle->name); $details = array( 'name' => $bundle->name, 'label' => $bundle->label, 'term' => array( 'accession' => $vocab->vocabulary . ':' . $term->accession, 'name' => $term->name, 'definition' => $term->definition, 'url' => $term->url ), 'fields' => array(), ); // Iterate through each feild and provide a discription of it and // it's sub elements. foreach ($instances as $instance) { // Skip deleted fields. if ($instance['deleted']) { continue; } $field_name = $instance['field_name']; $field = field_info_field($field_name); $field_class = $field['type']; $term_vocab = $instance['settings']['term_vocabulary']; $term_accession = $instance['settings']['term_accession']; $field_term = tripal_get_term_details($term_vocab, $term_accession); $field_details = array( 'name' => $field_name, 'label' => $instance['label'], 'term' => array( 'accession' => $term_vocab . ":" . $term_accession, 'name' => $field_term['name'], 'definition' => $field_term['definition'], 'url' => $field_term['url'], ), // These items can be overridden by the element_info array that // is present in a TripalField instance. Here we set defaults. 'required' => $instance['required'] ? TRUE : FALSE, 'type' => 'xs:string', 'readonly' => TRUE, // The cardinatlity value always comes from the field. 'cardinality' => $field['cardinality'], ); if (tripal_load_include_field_class($field_class)) { $field_obj = new $field_class($field, $instance); $element_info = $field_obj->elementInfo(); $element_info = $element_info[$term_vocab . ':' . $term_accession]; // If the element info for this field sets required, type and readonly // attributes then set those. $field_details['required'] = array_key_exists('required', $element_info) ? $element_info['required'] : FALSE; $field_details['type'] = array_key_exists('type', $element_info) ? $element_info['type'] : 'xs:string'; $field_details['readonly'] = array_key_exists('readonly', $element_info) ? $element_info['readonly'] : TRUE; $field_details['label'] = array_key_exists('label', $element_info) ? $element_info['label'] : $field_details['label']; $field_details['help'] = array_key_exists('help', $element_info) ? $element_info['help'] : ''; // If this field is an 'xs:complexType' then it will have sub elements. // we need to add those as well. if (array_key_exists('elements', $element_info) and is_array($element_info['elements'])) { _tripal_get_bundle_field_element_details($element_info['elements'], $field_details); } $details['fields'][] = $field_details; } } return $details; } /** * A recursive helper function for the tripal_get_bundle_details. * * @param $elementInfo * * @ingroup tripal_entities_api */ function _tripal_get_bundle_field_element_details($elements, &$field_details) { $field_details['elements'] = array(); foreach ($elements as $element_key => $element_info) { // Handle the entity element differnetly. if ($element_key == 'entity') { continue; } list($term_vocab, $term_accession) = explode(':', $element_key); $term = tripal_get_term_details($term_vocab, $term_accession); $element_details = array( 'name' => $element_info['name'], 'label' => array_key_exists('label', $element_info) ? $element_info['label'] : ucfirst(preg_replace('/_/', ' ', $term['name'])), 'help' => array_key_exists('help', $element_info) ? $element_info['help'] : '', 'term' => array( 'accession' => $term_vocab . ':' . $term_accession, 'name' => $term['name'], 'definition' => $term['definition'], 'url' => $term['url'], ), 'required' => array_key_exists('required', $element_info) ? $element_info['required'] : FALSE, 'type' => array_key_exists('type', $element_info) ? $element_info['type'] : 'xs:string', 'readonly' => array_key_exists('readonly', $element_info) ? $element_info['readonly'] : TRUE, ); if (array_key_exists('elements', $element_info) and is_array($element_info['elements'])) { _tripal_get_bundle_field_element_details($element_info['elements'], $element_details); } $field_details['elements'][] = $element_details; } } /** * * @param unknown $bundle_name * @param unknown $values * * @throws Exception * * @ingroup tripal_entities_api */ function tripal_insert_entity($bundle_name, $values){ global $user; $bundle = tripal_load_bundle_entity(array('name' => $bundle_name)); // Get the fields associated with this content type. $instances = field_info_instances('TripalEntity', $bundle->name); foreach ($instances as $instance) { $field_name = $instance['field_name']; $field = field_info_field($field_name); $field_type = $field['type']; $field_settings = $field['settings']; $instance_settings = $instance['settings']; $field_name = $field['field_name']; $vocabulary = $instance['settings']['term_vocabulary']; $accession = $instance['settings']['term_accession']; $field_accession = $vocabulary . ':' . $accession; $field_term = tripal_get_term_details($vocabulary, $accession); $field_key = $field_term['name']; $field_key = strtolower(preg_replace('/ /', '_', $key)); // There are three ways that a field value can be specified. Those // are as the controlled vocabulary accession (e.g. GO:0000134), sa // the field name or as the field key which is the term name with // spaces replaced with underscores. // First make sure that required fields are present. if ($instance['required'] == TRUE) { if (!array_key_exists($field_key, $values) and !array_key_exists($field_accession, $values) and !array_key_exists($field_name, $values)) { throw new Exception(t('Cannot insert the record. Missing the required field "%missing".', array('%missing' => $field_name))); } } } // Make sure that all required fields are presnet // TODO: make sure the user has permission to do this. $ec = entity_get_controller('TripalEntity'); $entity = $ec->create(array( 'bundle' => $bundle_name, 'term_id' => $bundle->term_id, )); $entity = $entity->save(); } /** * @param $bundle_name * @param $values * * @ingroup tripal_entities_api */ function tripal_update_entity($bundle_name, $values) { }