search_api_sorts.admin.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. <?php
  2. /**
  3. * Displays a form for selecting the indexed fields for which sorts should be
  4. * created.
  5. *
  6. * @param SearchApiIndex $index
  7. * The index for which to display the settings.
  8. */
  9. function search_api_sorts_index_select(array $form, array &$form_state, SearchApiIndex $index) {
  10. module_load_include('admin.inc', 'search_api');
  11. drupal_set_title(search_api_admin_item_title($index));
  12. $form_state['index'] = $index;
  13. if (!$index->server() || !$index->server()->supportsFeature('search_api_facets')) {
  14. // We can't offer any sorts, but maybe the user can delete old sort data.
  15. drupal_set_message(t("The server this index currently lies on doesn't support sorts. " .
  16. 'To use sorts, you will have to move this index to a server supporting this feature.'), 'error');
  17. return $form;
  18. }
  19. $sort_options = array('' => t('None'));
  20. $has_default = FALSE;
  21. $has_default_no_terms = FALSE;
  22. // get the sorts ordered by weight using EntityFieldQuery
  23. $query = new EntityFieldQuery;
  24. $results = $query
  25. ->entityCondition('entity_type', 'search_api_sort')
  26. ->propertyCondition('index_id', $index->machine_name)
  27. ->propertyOrderBy('weight', 'ASC')
  28. ->execute();
  29. $sort_ids = array();
  30. if (isset($results['search_api_sort'])) {
  31. foreach($results['search_api_sort'] as $result) {
  32. $sort_ids[] = $result->id;
  33. }
  34. }
  35. $sorts = search_api_sorts_load_multiple($sort_ids);
  36. foreach ($sorts as $sort) {
  37. if ($sort->enabled == 1) {
  38. $sort_options[$sort->field] = $sort->name;
  39. }
  40. if ($sort->default_sort) {
  41. $has_default = TRUE;
  42. }
  43. if ($sort->default_sort_no_terms) {
  44. $has_default_no_terms = TRUE;
  45. }
  46. }
  47. $form['description'] = array(
  48. '#type' => 'item',
  49. '#title' => t('Select the available sorts'),
  50. '#description' => t('<p>Only index single-value strings or numbers can be used as sorts. See the Fields tab to change indexes (tick the "Indexed" checkboxes).</p>'),
  51. );
  52. $form['sorts'] = array(
  53. '#tree' => TRUE,
  54. '#theme' => 'search_api_sorts_form_table',
  55. '#table_header' => array(
  56. t('Enabled'),
  57. t('Default'),
  58. t('Default (no terms)'),
  59. t('Sort'),
  60. t('Field'),
  61. t('Type'),
  62. t('Name'),
  63. t('Weight'),
  64. ),
  65. '#table_empty' => t('There are currently no fields for which sorts can be displayed.'),
  66. );
  67. // Add our dummy relevance field.
  68. $fields = array(
  69. 'search_api_relevance' => array(
  70. 'name' => 'Relevance',
  71. 'type' => 'decimal',
  72. 'indexed' => TRUE,
  73. ),
  74. ) + $index->getFields();
  75. if (!empty($fields)) {
  76. if ($disabled = empty($index->enabled)) {
  77. drupal_set_message('Since this index is at the moment disabled, no sorts can be activated.', 'warning');
  78. }
  79. $show_status = FALSE;
  80. foreach ($sorts as $sort) {
  81. $sorts[$sort->field][] = $sort;
  82. if (isset($sort->status) & ENTITY_IN_CODE) {
  83. $show_status = TRUE;
  84. }
  85. }
  86. if ($show_status) {
  87. $form['sorts']['#table_header'] = array(
  88. t('Enabled'),
  89. t('Default'),
  90. t('Default (no terms)'),
  91. t('Sort'),
  92. t('Status'),
  93. t('Field'),
  94. t('Type'),
  95. t('Name'),
  96. t('Weight'),
  97. );
  98. $empty_status = ' ';
  99. }
  100. $types = search_api_field_types();
  101. // need to get the index fields ordered by sort's weight
  102. $index_fields = $fields;
  103. foreach ($sorts as $key => $sort) {
  104. if (isset($fields[$key])) {
  105. $fields[$key]['weight'] = isset($sorts[$key][0]->weight) ? $sorts[$key][0]->weight : 0;
  106. $index_fields[$key] = $fields[$key];
  107. }
  108. }
  109. foreach ($fields as $key => $field) {
  110. if (!$field['indexed']) {
  111. continue;
  112. }
  113. // skip fulltext or multi-value, you cannot sort them
  114. if ($field['type'] == 'text' || strpos($field['type'], 'list<') !== FALSE) {
  115. continue;
  116. }
  117. $type = search_api_extract_inner_type($field['type']);
  118. $type = isset($types[$type]) ? $types[$type] : $type;
  119. if (empty($sorts[$key])) {
  120. $weight = 0;
  121. $sorts[$key][] = new SearchApiSort(array(
  122. 'index_id' => $index->machine_name,
  123. 'field' => $key,
  124. 'identifier' => $index->machine_name . '__' . $key,
  125. 'default_sort' => 0,
  126. 'default_sort_no_terms' => 0,
  127. 'default_order' => 'desc',
  128. 'name' => t('@field', array('@field' => $field['name'])),
  129. 'enabled' => 0,
  130. 'options' => array(),
  131. 'status' => 0,
  132. 'weight' => $weight,
  133. ));
  134. ++$weight;
  135. }
  136. foreach ($sorts[$key] as $i => $sort) {
  137. $k = $i ? "$key-$i" : $key;
  138. $form['sorts'][$k]['sort'] = array(
  139. '#type' => 'value',
  140. '#value' => $sort,
  141. );
  142. $form['sorts'][$k]['enabled'] = array(
  143. '#type' => 'checkbox',
  144. '#default_value' => $sort->enabled,
  145. '#disabled' => $disabled,
  146. );
  147. $form['sorts'][$k]['default_sort'] = array(
  148. '#type' => 'radio',
  149. '#return_value' => $k,
  150. '#tree' => FALSE,
  151. '#default_value' => $sort->default_sort ? $k : NULL,
  152. '#states' => array(
  153. 'enabled' => array(
  154. ':input[name="sorts[' . $k . '][enabled]"]' => array('checked' => TRUE),
  155. ),
  156. ),
  157. );
  158. $form['sorts'][$k]['default_sort_no_terms'] = array(
  159. '#type' => 'radio',
  160. '#return_value' => $k,
  161. '#tree' => FALSE,
  162. '#default_value' => $sort->default_sort_no_terms ? $k : NULL,
  163. '#states' => array(
  164. 'enabled' => array(
  165. ':input[name="sorts[' . $k . '][enabled]"]' => array('checked' => TRUE),
  166. ),
  167. ),
  168. );
  169. $form['sorts'][$k]['default_order'] = array(
  170. '#type' => 'select',
  171. '#default_value' => $sort->default_order,
  172. '#options' => array(
  173. 'asc' => t('Ascending'),
  174. 'desc' => t('Descending'),
  175. ),
  176. '#states' => array(
  177. 'visible' => array(
  178. ':input[name="sorts[' . $k . '][enabled]"]' => array('checked' => TRUE),
  179. ),
  180. ),
  181. );
  182. if ($show_status) {
  183. $form['sorts'][$k]['status']['#markup'] = $sort->status ? theme('entity_status', array('status' => $sort->status)) : $empty_status;
  184. }
  185. $form['sorts'][$k]['field'] = array(
  186. '#markup' => check_plain($field['name']),
  187. );
  188. $form['sorts'][$k]['type'] = array(
  189. '#markup' => $type,
  190. );
  191. $form['sorts'][$k]['name'] = array(
  192. '#type' => 'textfield',
  193. '#maxlength' => max(strlen($sort->name), 80),
  194. '#default_value' => $sort->name,
  195. );
  196. $form['sorts'][$k]['weight'] = array(
  197. '#type' => 'weight',
  198. '#default_value' => isset($sort->weight) ? (int) $sort->weight : 0,
  199. '#delta' => 100,
  200. '#attributes' => array(
  201. 'class' => array('search-api-sorts-weight'),
  202. ),
  203. );
  204. }
  205. }
  206. }
  207. $form['submit'] = array(
  208. '#type' => 'submit',
  209. '#value' => t('Save settings'),
  210. );
  211. return $form;
  212. }
  213. /**
  214. * Validation callback for search_api_sorts_index_select().
  215. */
  216. function search_api_sorts_index_select_validate(array $form, array &$form_state) {
  217. $warn = FALSE;
  218. foreach ($form_state['values']['sorts'] as $key => $v) {
  219. if ($v['enabled']) {
  220. // -> This setting will be stored.
  221. if (!$v['name']) {
  222. form_set_error("sorts][$key][name", t("You can't set an empty name."));
  223. }
  224. elseif (strlen($v['name']) > 80) {
  225. form_set_error("sorts][$key][name", t('Names cannot be longer than 80 characters, but "@name" is @count characters long.',
  226. array('@name' => $v['name'], '@count' => strlen($v['name']))));
  227. }
  228. }
  229. elseif ($v['sort']->name != $v['name']) {
  230. $warn = TRUE;
  231. }
  232. }
  233. if ($warn) {
  234. drupal_set_message(t('Note that changed names of sorts that are disabled and have no settings yet, are not saved.'), 'warning');
  235. }
  236. }
  237. /**
  238. * Submit callback for search_api_sorts_index_select().
  239. */
  240. function search_api_sorts_index_select_submit(array $form, array &$form_state) {
  241. $index = $form_state['index'];
  242. $count = 0;
  243. $delete_count = 0;
  244. $reset_count = 0;
  245. $counts = array();
  246. foreach ($form_state['values']['sorts'] as $key => $v) {
  247. $field = $v['sort']->field;
  248. $c = $counts[$field] = (isset($counts[$field]) ? $counts[$field] + 1 : 1);
  249. if (empty($v['enabled']) || (isset($v['sort']->status) && $v['sort']->status == ENTITY_OVERRIDDEN)) {
  250. // This is the only case in which a "delete" makes sense.
  251. if (!empty($v['delete'])) {
  252. $v['sort']->delete();
  253. $v['sort']->status == ENTITY_OVERRIDDEN ? ++$reset_count : ++$delete_count;
  254. continue;
  255. }
  256. }
  257. $f = $v['sort'];
  258. $default_sort = $form_state['values']['default_sort'] == $key;
  259. $default_sort_no_terms = $form_state['values']['default_sort_no_terms'] == $key;
  260. $update = $f->enabled != $v['enabled'] || $f->name != $v['name'] || $f->weight != $v['weight'] || $f->default_sort != $default_sort || $f->default_sort_no_terms != $default_sort_no_terms || $f->default_order != $v['default_order'];
  261. if ($update) {
  262. $f = clone $f;
  263. $f->enabled = $v['enabled'];
  264. $f->name = $v['name'];
  265. $f->default_sort = $default_sort;
  266. $f->default_sort_no_terms = $default_sort_no_terms;
  267. $f->default_order = $v['default_order'];
  268. $f->weight = $v['weight'];
  269. $f->save();
  270. ++$count;
  271. }
  272. }
  273. if ($delete_count) {
  274. drupal_set_message(format_plural($delete_count, 'The settings of 1 sort were successfully deleted.', 'The settings of @count sorts were successfully deleted.'));
  275. }
  276. if ($count) {
  277. drupal_set_message(format_plural($count, '1 sort was successfully updated.', '@count sorts were successfully updated.'));
  278. }
  279. if ($reset_count) {
  280. drupal_set_message(format_plural($reset_count, '1 sort configuration was reset.', '@count sort configurations were reset.'));
  281. }
  282. if (!($count + $delete_count + $reset_count)) {
  283. drupal_set_message(t('No values were changed.'));
  284. }
  285. }
  286. /**
  287. * Theming function for rendering a form as a table.
  288. *
  289. * @param array $variables
  290. * An array of variables to use, containing only one entry:
  291. * - element: The sub-form to render as a table.
  292. *
  293. * @return string
  294. * HTML displaying the specified sub-form as a table.
  295. */
  296. function theme_search_api_sorts_form_table(array $variables) {
  297. $form = $variables['element'];
  298. $rows = array();
  299. foreach (element_children($form) as $id) {
  300. $row = array();
  301. foreach (element_children($form[$id]) as $field) {
  302. if ($cell = render($form[$id][$field])) {
  303. $row[] = $cell;
  304. }
  305. }
  306. $rows[] = array(
  307. 'data' => $row,
  308. 'class' => array('draggable'),
  309. );
  310. }
  311. $vars['rows'] = $rows;
  312. if (isset($form['#table_header'])) {
  313. $vars['header'] = $form['#table_header'];
  314. }
  315. if (isset($form['#table_empty'])) {
  316. $vars['empty'] = $form['#table_empty'];
  317. }
  318. $vars['attributes']['id'] = 'search-api-sorts-table';
  319. drupal_add_tabledrag('search-api-sorts-table', 'order', 'sibling', 'search-api-sorts-weight');
  320. return theme('table', $vars);
  321. }