query.inc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php
  2. /**
  3. * Views query class using a Search API index as the data source.
  4. */
  5. class SearchApiMultiViewsQuery extends SearchApiViewsQuery {
  6. /**
  7. * The server this view accesses.
  8. *
  9. * @var SearchApiServer
  10. */
  11. protected $server;
  12. /**
  13. * Create the basic query object and fill with default values.
  14. */
  15. public function init($base_table, $base_field, $options) {
  16. try {
  17. parent::init($base_table, $base_field, $options);
  18. if (substr($base_table, 0, 18) == 'search_api_server_') {
  19. $id = substr($base_table, 18);
  20. $this->server = search_api_server_load($id);
  21. $this->query = $this->server->queryMultiple(array(
  22. 'parse mode' => 'terms',
  23. ));
  24. }
  25. }
  26. catch (Exception $e) {
  27. $this->errors[] = $e->getMessage();
  28. }
  29. }
  30. /**
  31. * Helper function for adding results to a view in the format expected by the view.
  32. */
  33. protected function addResults(array $results, $view) {
  34. $index_types = array();
  35. $view_result = array();
  36. $items = array();
  37. $ids = array();
  38. // First we extract the involved indexes, and which entities need to be
  39. // loaded for each entity type.
  40. foreach ($results as $result) {
  41. $id = $result['id'];
  42. $index_id = $result['index_id'];
  43. if (!isset($index_types[$index_id])) {
  44. $index_types[$index_id] = search_api_index_load($index_id)->item_type;
  45. }
  46. // Maybe the service class or a postprocessor already set the entities.
  47. if (!empty($result['entity'])) {
  48. $items[$index_types[$index_id]][$id] = $result['entity'];
  49. }
  50. else {
  51. $ids[$index_types[$index_id]][$id] = $id;
  52. }
  53. }
  54. // Then extract the needed fields for each involved entity type.
  55. $type_fields = array();
  56. foreach ($this->fields as $field => $true) {
  57. if (strpos($field, ':') !== FALSE) {
  58. list($index_id, $field) = explode(':', $field, 2);
  59. if (isset($index_types[$index_id])) {
  60. $type_fields[$index_types[$index_id]][$field] = TRUE;
  61. }
  62. }
  63. }
  64. // Extract the field values for entities that were already loaded.
  65. foreach ($items as $type => $objs) {
  66. foreach ($objs as $id => $item) {
  67. try {
  68. $key = $type . '-' . $id;
  69. $wrapper = search_api_get_datasource_controller($type)->getMetadataWrapper($item);
  70. $view_result[$key] = (object) $this->extractFields($wrapper, $type_fields[$type]);
  71. $view_result[$key]->entity = $item;
  72. unset($objs[$id]);
  73. }
  74. catch (Exception $e) {
  75. continue;
  76. }
  77. }
  78. // If the values of some items couldn't be extracted, try it again with
  79. // freshly loaded ones.
  80. if ($objs) {
  81. $ids[$type] = array_merge($ids[$type], array_keys($objs));
  82. }
  83. }
  84. // Load remaining items and extract their field values.
  85. foreach ($ids as $type => $item_ids) {
  86. if (empty($type_fields[$type])) {
  87. continue;
  88. }
  89. $datasource = search_api_get_datasource_controller($type);
  90. $items = $datasource->loadItems($item_ids);
  91. foreach ($items as $id => $item) {
  92. try {
  93. $key = $type . '-' . $id;
  94. $wrapper = $datasource->getMetadataWrapper($item);
  95. $view_result[$key] = (object) $this->extractFields($wrapper, $type_fields[$type]);
  96. $view_result[$key]->entity = $item;
  97. }
  98. catch (Exception $e) {
  99. continue;
  100. }
  101. }
  102. }
  103. // Finally, add the extracted values in the correct order to $view->result.
  104. foreach ($results as $result) {
  105. $key = $index_types[$result['index_id']] . '-' . $result['id'];
  106. if (isset($view_result[$key])) {
  107. $prefix = $result['index_id'] . ':';
  108. $view->result[$key] = new stdClass();
  109. foreach ($view_result[$key] as $k => $v) {
  110. if ($k != 'entity') {
  111. $k = $prefix . $k;
  112. }
  113. $view->result[$key]->$k = $v;
  114. }
  115. $view->result[$key]->search_api_relevance = $result['score'];
  116. $view->result[$key]->search_api_multi_index = $result['index_id'];
  117. foreach ($this->fields as $field => $true) {
  118. if (!isset($view->result[$key]->$field)) {
  119. $view->result[$key]->$field = '';
  120. }
  121. }
  122. }
  123. }
  124. }
  125. //
  126. // Query interface methods (proxy to $this->query)
  127. //
  128. public function getServer() {
  129. return $this->server;
  130. }
  131. public function getIndexes() {
  132. if (!$this->errors) {
  133. return $this->query->getIndexes();
  134. }
  135. }
  136. }