TripalFieldQuery.inc

File

tripal/includes/TripalFieldQuery.inc
View source
  1. <?php
  2. /**
  3. * Extends the EntityFieldQuery to support queries from multiple storage types.
  4. */
  5. class TripalFieldQuery extends EntityFieldQuery {
  6. /**
  7. * Holds a list of fields that should be included in the results
  8. */
  9. protected $includes = array();
  10. /**
  11. * Overrides the EntityFieldQuery::execute() function.
  12. */
  13. public function execute() {
  14. // Give a chance for other modules to alter the query.
  15. drupal_alter('entity_query', $this);
  16. $this->altered = TRUE;
  17. // Initialize the pager.
  18. $this->initializePager();
  19. // If there are fields then we need to support multiple backends, call
  20. // the function for each one and merge the results.
  21. if ($this->fields) {
  22. // Build the list of all of the different field storage types used
  23. // for this query.
  24. foreach ($this->fields as $field) {
  25. $this->field_storage[$field['storage']['type']] = $field['storage']['module'];
  26. }
  27. // Initialize the results array.
  28. $results = array();
  29. // Iterate through the field storage types and call each one.
  30. foreach ($this->field_storage as $storage_type => $storage_module) {
  31. // Execute the query using the correct callback.
  32. $callback = $this->queryStorageCallback($storage_module);
  33. $st_results = call_user_func($callback, $this);
  34. // If this is the first storage type to be queries then save these
  35. // as the current results list.
  36. if (count($results) == 0) {
  37. $results = $st_results;
  38. }
  39. // If other results already exist then we want to find the intersection
  40. // of the two and only save those.
  41. else {
  42. $intersection = array(
  43. 'TripalEntity' => array(),
  44. );
  45. foreach ($st_results['TripalEntity'] as $entity_id => $stub) {
  46. if (array_key_exists($entity_id, $results['TripalEntity'])) {
  47. $intersection['TripalEntity'][$entity_id] = $stub;
  48. }
  49. }
  50. $results = $intersection;
  51. }
  52. }
  53. }
  54. // If there are no fields then default to the original
  55. // EntityFieldQuery() functionality.
  56. else {
  57. $results = call_user_func($this->queryCallback(), $this);
  58. }
  59. if ($results and $this->count) {
  60. if (!is_numeric($results)) {
  61. throw new Exception('Query callback function did not provide a numeric value: ' . $this->queryCallback());
  62. }
  63. return $results;
  64. }
  65. else {
  66. return $results;
  67. }
  68. }
  69. /**
  70. * Determines the query callback to use for this entity query.
  71. *
  72. * This function is a replacement for queryCallback() from the
  73. * parent EntityFieldQuery class because that class only allows a single
  74. * storage type per query.
  75. *
  76. * @param $storage
  77. * The storage module
  78. *
  79. * @throws EntityFieldQueryException
  80. * @return
  81. * A callback that can be used with call_user_func().
  82. *
  83. */
  84. protected function queryStorageCallback($storage) {
  85. // Use the override from $this->executeCallback. It can be set either
  86. // while building the query, or using hook_entity_query_alter().
  87. if (function_exists($this->executeCallback)) {
  88. return $this->executeCallback;
  89. }
  90. // If there are no field conditions and sorts, and no execute callback
  91. // then we default to querying entity tables in SQL.
  92. if (empty($this->fields)) {
  93. return array($this, 'propertyQuery');
  94. }
  95. if ($storage) {
  96. // Use hook_field_storage_query() from the field storage.
  97. return $storage . '_field_storage_query';
  98. }
  99. else {
  100. throw new EntityFieldQueryException(t("Field storage engine not found."));
  101. }
  102. }
  103. }