display_facet_block.inc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <?php
  2. /**
  3. * @file
  4. * Display plugin for displaying the search facets in a block.
  5. */
  6. /**
  7. * Plugin class for displaying search facets in a block.
  8. */
  9. class SearchApiViewsFacetsBlockDisplay extends views_plugin_display_block {
  10. public function displays_exposed() {
  11. return FALSE;
  12. }
  13. public function uses_exposed() {
  14. return FALSE;
  15. }
  16. public function option_definition() {
  17. $options = parent::option_definition();
  18. $options['linked_path'] = array('default' => '');
  19. $options['facet_field'] = '';
  20. $options['hide_block'] = FALSE;
  21. return $options;
  22. }
  23. public function options_form(&$form, &$form_state) {
  24. parent::options_form($form, $form_state);
  25. if (substr($this->view->base_table, 0, 17) != 'search_api_index_') {
  26. return;
  27. }
  28. switch ($form_state['section']) {
  29. case 'linked_path':
  30. $form['#title'] .= t('Search page path');
  31. $form['linked_path'] = array(
  32. '#type' => 'textfield',
  33. '#description' => t('The menu path to which search facets will link. Leave empty to use the current path.'),
  34. '#default_value' => $this->get_option('linked_path'),
  35. );
  36. break;
  37. case 'facet_field':
  38. $form['facet_field'] = array(
  39. '#type' => 'select',
  40. '#title' => t('Facet field'),
  41. '#options' => $this->getFieldOptions(),
  42. '#default_value' => $this->get_option('facet_field'),
  43. );
  44. break;
  45. case 'use_more':
  46. $form['use_more']['#description'] = t('This will add a more link to the bottom of this view, which will link to the base path for the facet links.');
  47. $form['use_more_always'] = array(
  48. '#type' => 'value',
  49. '#value' => $this->get_option('use_more_always'),
  50. );
  51. break;
  52. case 'hide_block':
  53. $form['hide_block'] = array(
  54. '#type' => 'checkbox',
  55. '#title' => t('Hide block'),
  56. '#description' => t('Hide this block, but still execute the search. ' .
  57. 'Can be used to show native Facet API facet blocks linking to the search page specified above.'),
  58. '#default_value' => $this->get_option('hide_block'),
  59. );
  60. break;
  61. }
  62. }
  63. public function options_validate(&$form, &$form_state) {
  64. if (substr($this->view->base_table, 0, 17) != 'search_api_index_') {
  65. form_set_error('', t('The "Facets block" display can only be used with base tables based on Search API indexes.'));
  66. }
  67. }
  68. public function options_submit(&$form, &$form_state) {
  69. parent::options_submit($form, $form_state);
  70. switch ($form_state['section']) {
  71. case 'linked_path':
  72. $this->set_option('linked_path', $form_state['values']['linked_path']);
  73. break;
  74. case 'facet_field':
  75. $this->set_option('facet_field', $form_state['values']['facet_field']);
  76. break;
  77. case 'hide_block':
  78. $this->set_option('hide_block', $form_state['values']['hide_block']);
  79. break;
  80. }
  81. }
  82. public function options_summary(&$categories, &$options) {
  83. parent::options_summary($categories, $options);
  84. $options['linked_path'] = array(
  85. 'category' => 'block',
  86. 'title' => t('Search page path'),
  87. 'value' => $this->get_option('linked_path') ? $this->get_option('linked_path') : t('Use current path'),
  88. );
  89. $field_options = $this->getFieldOptions();
  90. $options['facet_field'] = array(
  91. 'category' => 'block',
  92. 'title' => t('Facet field'),
  93. 'value' => $this->get_option('facet_field') ? $field_options[$this->get_option('facet_field')] : t('None'),
  94. );
  95. $options['hide_block'] = array(
  96. 'category' => 'block',
  97. 'title' => t('Hide block'),
  98. 'value' => $this->get_option('hide_block') ? t('Yes') : t('No'),
  99. );
  100. }
  101. protected $field_options = NULL;
  102. protected function getFieldOptions() {
  103. if (!isset($this->field_options)) {
  104. $index_id = substr($this->view->base_table, 17);
  105. if (!($index_id && ($index = search_api_index_load($index_id)))) {
  106. $table = views_fetch_data($this->view->base_table);
  107. $table = empty($table['table']['base']['title']) ? $this->view->base_table : $table['table']['base']['title'];
  108. throw new SearchApiException(t('The "Facets block" display cannot be used with a view for @basetable. ' .
  109. 'Please only use this display with base tables representing search indexes.',
  110. array('@basetable' => $table)));
  111. }
  112. $this->field_options = array();
  113. if (!empty($index->options['fields'])) {
  114. foreach ($index->getFields() as $key => $field) {
  115. $this->field_options[$key] = $field['name'];
  116. }
  117. }
  118. }
  119. return $this->field_options;
  120. }
  121. /**
  122. * Render the 'more' link
  123. */
  124. public function render_more_link() {
  125. if ($this->use_more()) {
  126. $path = $this->get_option('linked_path');
  127. $theme = views_theme_functions('views_more', $this->view, $this->display);
  128. $path = check_url(url($path, array()));
  129. return array(
  130. '#theme' => $theme,
  131. '#more_url' => $path,
  132. '#link_text' => check_plain($this->use_more_text()),
  133. );
  134. }
  135. }
  136. public function execute() {
  137. if (substr($this->view->base_table, 0, 17) != 'search_api_index_') {
  138. form_set_error('', t('The "Facets block" display can only be used with base tables based on Search API indexes.'));
  139. return NULL;
  140. }
  141. $facet_field = $this->get_option('facet_field');
  142. if (!$facet_field) {
  143. return NULL;
  144. }
  145. $base_path = $this->get_option('linked_path');
  146. if (!$base_path) {
  147. $base_path = $_GET['q'];
  148. }
  149. $this->view->build();
  150. $limit = empty($this->view->query->pager->options['items_per_page']) ? 10 : $this->view->query->pager->options['items_per_page'];
  151. $query_options = &$this->view->query->getOptions();
  152. if (!$this->get_option('hide_block')) {
  153. // If we hide the block, we don't need this extra facet.
  154. $query_options['search_api_facets']['search_api_views_facets_block'] = array(
  155. 'field' => $facet_field,
  156. 'limit' => $limit,
  157. 'missing' => FALSE,
  158. 'min_count' => 1,
  159. );
  160. }
  161. $query_options['search id'] = 'search_api_views:' . $this->view->name . '-facets_block';
  162. $query_options['search_api_base_path'] = $base_path;
  163. $this->view->query->range(0, 0);
  164. $this->view->execute();
  165. if ($this->get_option('hide_block')) {
  166. return NULL;
  167. }
  168. $results = $this->view->query->getSearchApiResults();
  169. if (empty($results['search_api_facets']['search_api_views_facets_block'])) {
  170. return NULL;
  171. }
  172. $terms = $results['search_api_facets']['search_api_views_facets_block'];
  173. $filters = array();
  174. foreach ($terms as $term) {
  175. $filter = $term['filter'];
  176. if ($filter[0] == '"') {
  177. $filter = substr($filter, 1, -1);
  178. }
  179. elseif ($filter != '!') {
  180. // This is a range filter.
  181. $filter = substr($filter, 1, -1);
  182. $pos = strpos($filter, ' ');
  183. if ($pos !== FALSE) {
  184. $filter = '[' . substr($filter, 0, $pos) . ' TO ' . substr($filter, $pos + 1) . ']';
  185. }
  186. }
  187. $filters[$term['filter']] = $filter;
  188. }
  189. $index = $this->view->query->getIndex();
  190. $options['field'] = $index->options['fields'][$facet_field];
  191. $options['field']['key'] = $facet_field;
  192. $options['index id'] = $index->machine_name;
  193. $options['value callback'] = '_search_api_facetapi_facet_create_label';
  194. $map = search_api_facetapi_facet_map_callback($filters, $options);
  195. $facets = array();
  196. $prefix = rawurlencode($facet_field) . ':';
  197. foreach ($terms as $term) {
  198. $name = $filter = $filters[$term['filter']];
  199. if (isset($map[$filter])) {
  200. $name = $map[$filter];
  201. }
  202. $query['f'][0] = $prefix . $filter;
  203. // Initializes variables passed to theme hook.
  204. $variables = array(
  205. 'text' => $name,
  206. 'path' => $base_path,
  207. 'count' => $term['count'],
  208. 'options' => array(
  209. 'attributes' => array('class' => 'facetapi-inactive'),
  210. 'html' => FALSE,
  211. 'query' => $query,
  212. ),
  213. );
  214. // Themes the link, adds row to facets.
  215. $facets[] = array(
  216. 'class' => array('leaf'),
  217. 'data' => theme('facetapi_link_inactive', $variables),
  218. );
  219. }
  220. if (!$facets) {
  221. return NULL;
  222. }
  223. $info['content']['facets'] = array(
  224. '#theme' => 'item_list',
  225. '#items' => $facets,
  226. );
  227. $info['content']['more'] = $this->render_more_link();
  228. $info['subject'] = filter_xss_admin($this->view->get_title());
  229. return $info;
  230. }
  231. }