Răsfoiți Sursa

Adding a new TripalFieldQuery class for querying of TripalEntities

Stephen Ficklin 8 ani în urmă
părinte
comite
b0f4febd76

+ 9 - 29
tripal/includes/TripalEntityUIController.inc

@@ -205,42 +205,22 @@ function tripal_view_entity($entity, $view_mode = 'full') {
      '#value' => 'Filter',
    );
 
-   // Retrieve a pages list of all tripal entitles (ie: biological data).
-   // This will return the 25 most recently created entities.
-   $query = db_select('tripal_entity', 'td')
-     ->fields('td');
+   $query = new TripalFieldQuery();
    if ($filter_type) {
-     $query = $query->condition('term_id', $filter_type);
+     $query = $query->fieldCondition('content_type', $filter_type);
    }
-   if (is_numeric($filter_status)) {
-     $query = $query->condition('status', $filter_status);
-   }
-   $entities = $query->orderBy('created', 'DESC')
-     ->range(0,25)
-     ->execute();
-
-   global $user;
-   $query = new EntityFieldQuery();
-   $query->entityCondition('entity_type', 'TripalEntity');
-   if ($filter_type) {
-     $query = $query->propertyCondition('term_id', $filter_type);
-   }
-   if (is_numeric($filter_status)) {
-     $query = $query->propertyCondition('status', $filter_status);
-   }
-//   $query = $query->fieldCondition('feature__name', 'value', 'orange1.1g022797m');
-//   $query = $query->fieldCondition('feature__uniquename', 'value', 'PAC:18136225');
-
-   $result = $query->range(0, 25)
-     ->addMetaData('account', $user)
-     ->execute();
+   //
+   //$query = $query->fieldCondition('feature__name', 'orange1', 'STARTS WITH');
+   $results = $query->execute();
 
    $headers = array('Title', 'Vocabulary', 'Term', 'Author', 'Status', 'Updated', 'Operations');
    $rows = array();
 
    // For each entity retrieved add a row to the data listing.
-   while ($entity = $entities->fetchObject()) {
-
+   //while ($entity = $entities->fetchObject()) {
+   foreach ($results['TripalEntity'] as $entity_id => $stub) {
+     $entity = entity_load('TripalEntity', array($entity_id));
+     $entity = reset($entity);
      $namespace = '';
      $term_name = '';
 

+ 109 - 0
tripal/includes/TripalFieldQuery.inc

@@ -0,0 +1,109 @@
+<?php
+
+
+/**
+ * A simple class for querying entities based on field values for fields.
+ *
+ * This class supports the use of multiple field storage. This class is loosely
+ * modeled after the EntityFieldQuery class.
+ *
+ */
+class TripalFieldQuery {
+
+
+  // A list of the field storage instances for the fields in the filter.
+  protected $field_storage = array();
+  // The order in which the field storage execute() function should be
+  // called.
+  protected $fs_order = array();
+  // An associative array of the filters to apply.
+  protected $conditions = array();
+
+  /**
+   *
+   * @param $field_name
+   *   The name of the field.
+   * @param $value
+   *   The value to use for filtering.
+   * @param $operator
+   *   The operation to apply: '=', '<>', '>', '>=', '<', '<=', 'STARTS_WITH',
+   *   'CONTAINS': These operators expect $value to be a literal of the same
+   *   type as the column. 'IN', 'NOT IN': These operators expect $value to
+   *   be an array of literals of the same type as the column.
+   */
+  public function fieldCondition($field_name, $value, $operator = '=') {
+    $field = field_info_field($field_name);
+    if ($field) {
+      $field_storage_type = $field['storage']['type'];
+      $this->conditions[$field_storage_type][] = array(
+        'field' => $field,
+        'value' => $value,
+        'operator' => $operator,
+      );
+      if (!array_key_exists($field_storage_type, $this->field_storage)) {
+        $this->field_storage[$field_storage_type] = $field['storage'];
+        $this->fs_order[] = $field_storage_type;
+      }
+    }
+    return $this;
+  }
+
+  /**
+   * Executes the query and returns results.
+   *
+   * This function does not actually perform any queries itself but passes
+   * on the task to field storage backends for all of the fields in the
+   * filter.  Each backend should return a list of entity IDs that match
+   * the filters provided. The intersection of this list is returned.
+   *
+   * @return
+   *  An array of associative arrays of stub entities. The result can be
+   *  used in the same way that results from the EntityFieldQuery->execute()
+   *  function are used.
+   */
+  public function execute() {
+    // Are there any conditions?  If so, then let the field storage
+    // systems handle the query. If there are no fields then just pull out
+    // the list of entities.
+    $entity_ids = array();
+    if (count($this->conditions) > 0) {
+      // Iterate through each of the field storage types and run their
+      // tquery() function.
+      foreach ($this->fs_order as $field_storage_type) {
+        $storage = $this->field_storage[$field_storage_type];
+        $module = $storage['module'];
+        $function_name = $module . '_field_storage_tquery';
+        $filter_ids = array();
+        if (function_exists($function_name)) {
+          $filter_ids = $function_name($this->conditions[$field_storage_type]);
+        }
+        // Take the intersection of IDs in this filter with those in the
+        // final $entity_ids;
+        if (count($entity_ids) == 0) {
+          $entity_ids = $filter_ids;
+        }
+        else {
+          $entity_ids = array_intersect($entity_ids, $filter_ids);
+        }
+      }
+    }
+    else {
+      $query = db_select('tripal_entity', 'td');
+      $query->fields('td', array('id'));
+      $query->orderBy('created', 'DESC');
+      $query->range(0,25);
+      $results = $query->execute();
+      while ($entity_id = $results->fetchField()) {
+        $entity_ids[] = $entity_id;
+      }
+    }
+
+    // Generate the entities for the keys.
+    $return = array();
+    foreach ($entity_ids as $entity_id) {
+      $entity = entity_create_stub_entity('TripalEntity', array($entity_id, NULL, NULL));
+      $return['TripalEntity'][$entity_id] = $entity;
+    }
+    return $return;
+  }
+}

+ 0 - 9
tripal/includes/TripalFieldStorage.inc

@@ -1,9 +0,0 @@
-<?php
-
-
-/**
- * A base class for all field storage mechanisms supported by Tripal.
- *
- */
-class TripalFieldStorage {
-}

+ 46 - 4
tripal/includes/tripal.field_storage.inc

@@ -64,12 +64,54 @@ function tripal_field_storage_load($entity_type, $entities, $age,
 /**
  * Implements hook_field_storage_query().
  *
- * Used by EntityFieldQuery to find the entities having certain entity
- * and field conditions and sort them in the given field order.
+ * Used by EntityFieldQuery to find the entities having certain field values.
  *
- * NOTE: This function needs to exist or errors are triggered but so far it doesn't
- * appear to actually need to do anything...
+ * We do not support use of the EntityFieldQuery API for Tripal based fields
+ * because EFQ doesn't support when multiple storage backends are used. Instead
+ * use the TripalFieldQuery class and implement the hook_storage_tquery()
+ * function.
  */
 function tripal_field_storage_query($query) {
 
+}
+
+/**
+ * Implements hook_field_storage_tquery().
+ *
+ * Used by TripalFieldQuery to find the entities having certain field values.
+ *
+ * @param $conditions
+ */
+function tripal_field_storage_tquery($conditions) {
+  $filter = array();
+  $entity_ids = array();
+  foreach ($conditions as $index => $condition) {
+    $field = $condition['field'];
+    $field_type = $field['type'];
+    $field_module = $field['module'];
+    $settings = $field['settings'];
+    $operator = $condition['operator'];
+
+    // This module only supports one field, so we can just perform the filter.
+    // using the appropriate operator.
+    $query = db_select('tripal_entity', 'TE');
+    $query->join('chado_entity', 'CE', 'TE.id = CE.entity_id');
+    $query->fields('CE', array('entity_id'));
+    $query->condition('TE.term_id', $condition['value'], $operator);
+    $results = $query->execute();
+    $filter_ids = array();
+    while ($entity_id = $results->fetchField()) {
+      $filter_ids[] = $entity_id;
+    }
+
+    // Take the intersection of IDs in this filter with those in the
+    // final $entity_ids;
+    if (count($entity_ids) == 0) {
+      $entity_ids = $filter_ids;
+    }
+    else {
+      $entity_ids = array_intersect($entity_ids, $filter_ids);
+    }
+  }
+  return $entity_ids;
 }

+ 1 - 1
tripal/tripal.module

@@ -25,7 +25,7 @@ require_once "includes/TripalBundle.inc";
 require_once "includes/TripalBundleController.inc";
 require_once "includes/TripalBundleUIController.inc";
 require_once "includes/TripalField.inc";
-
+require_once "includes/TripalFieldQuery.inc";
 
 /**
  * @defgroup tripal Tripal Core Module

+ 115 - 12
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -38,7 +38,7 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
   $base_pkey = $base_schema['primary key'][0];
 
   // Convert the fields into a key/value list of fields and their values.
-  $field_vals = tripal_chado_field_storage_merge_fields($fields, $entity_type, $entity);
+  $field_vals = tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity);
 
   // Write the record for the base table.  First get the values for this table
   // and set the record_id (update) or the type_id (insert)
@@ -296,7 +296,9 @@ function tripal_chado_field_storage_load($entity_type, $entities, $age,
 
         if (preg_match('/^chado/', $field_type) and class_exists($field_type)) {
           $field_obj = new $field_type();
-          $field_obj->load($field, $entity, array('record' => $record));
+          if (method_exists($field_obj, 'load')) {
+            $field_obj->load($field, $entity, array('record' => $record));
+          }
         }
 
         if (function_exists($load_function)) {
@@ -310,7 +312,7 @@ function tripal_chado_field_storage_load($entity_type, $entities, $age,
 /**
  * Merges the values of all fields into a single array keyed by table name.
  */
-function tripal_chado_field_storage_merge_fields($fields, $entity_type, $entity) {
+function tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity) {
   $new_fields = array();
 
   // Iterate through all of the fields and organize them into a
@@ -408,17 +410,118 @@ function tripal_chado_field_storage_expand_field($item_name, $value) {
 /**
  * Implements hook_field_storage_query().
  *
- * Used by EntityFieldQuery to find the entities having certain entity
- * and field conditions and sort them in the given field order.
+ * Used by EntityFieldQuery to find the entities having certain field values.
  *
- * NOTE: This function needs to exist or errors are triggered but so far it doesn't
- * appear to actually need to do anything...
+ * We do not support use of the EntityFieldQuery API for Tripal based fields
+ * because EFQ doesn't support when multiple storage backends are used. Instead
+ * use the TripalFieldQuery class and implement the hook_storage_tquery()
+ * function.
  */
 function tripal_chado_field_storage_query($query) {
-  $fieldConditions = $query->fieldConditions;
-  foreach ($fieldConditions as $condition) {
+
+}
+/**
+ * Implements hook_field_storage_tquery().
+ *
+ * Used by TripalFieldQuery to find the entities having certain field values.
+ *
+ * @param $conditions
+ */
+function tripal_chado_field_storage_tquery($conditions) {
+  $filter = array();
+  foreach ($conditions as $index => $condition) {
     $field = $condition['field'];
-    $field_name = $field['field_name'];
-    $column = $condition['column'];
+    $field_type = $field['type'];
+    $field_module = $field['module'];
+    $settings = $field['settings'];
+    $chado_table = $settings['chado_table'];
+    $chado_column = $settings['chado_column'];
+
+    // Allow the creating module to alter the value if desired.
+    $value = '';
+    module_load_include('inc', $field_module, 'includes/fields/' . $field_type);
+    if (preg_match('/^chado/', $field_type) and class_exists($field_type)) {
+      $field_obj = new $field_type();
+      if (method_exists($field_obj, 'query')) {
+        $value = $field_obj->query($condition);
+      }
+    }
+    // If there is no field to rewrite the value then use defaults.
+    else {
+      $value = $condition['value'];
+    }
+
+    // use the appropriate operator.
+    $operator = $condition['operator'];
+    switch ($operator) {
+      case '=':
+        $filter[$chado_table][$chado_column] = $condition['value'];
+        break;
+      case '>':
+      case '>=':
+      case '<':
+      case '<=':
+        $filter[$chado_table][$chado_column] = array(
+          'op' => $operator,
+          'data' => $value,
+        );
+        break;
+      case '<>':
+        $filter[$chado_table][$chado_column] = array(
+          'op' => 'NOT',
+          'data' => $value,
+        );
+        break;
+      case 'CONTAINS':
+        break;
+        $filter[$chado_table][$chado_column] = array(
+          'op' => 'LIKE',
+          'data' => '%' . $value . '%',
+        );
+      case 'STARTS WITH':
+        $filter[$chado_table][$chado_column] = array(
+          'op' => 'LIKE',
+          'data' => $value . '%',
+        );
+        break;
+      default:
+        // unrecognized operation.
+        break;
+    }
   }
-}
+
+  // Iterate through the filters and perform the query
+  $entity_ids = array();
+  foreach ($filter as $chado_table => $values) {
+    // First get the matching record IDs from the Chado table.
+    $schema = chado_get_schema($chado_table);
+    $pkey = $schema['primary key'][0];
+    $results = chado_select_record($chado_table, array($pkey), $values);
+
+    $record_ids = array();
+    foreach ($results as $result) {
+      $record_ids[] = $result->$pkey;
+    }
+
+    // Next look for matching IDs in the chado_entity table.
+    $filter_ids = array();
+    $results = db_select('chado_entity', 'CE')
+      ->fields('CE', array('entity_id'))
+      ->condition('record_id', $record_ids)
+      ->execute();
+    while ($result = $results->fetchObject()) {
+      $filter_ids[] = $result->entity_id;
+    }
+
+    // Take the intersection of IDs in this filter with those in the
+    // final $entity_ids;
+    if (count($entity_ids) == 0) {
+      $entity_ids = $filter_ids;
+    }
+    else {
+      $entity_ids = array_intersect($entity_ids, $filter_ids);
+    }
+  }
+
+  return $entity_ids;
+}