search_api.install 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. <?php
  2. /**
  3. * @file
  4. * Install, update and uninstall functions for the Search API module.
  5. */
  6. use Drupal\Component\Render\FormattableMarkup;
  7. use Drupal\Core\Link;
  8. use Drupal\search_api\Entity\Server;
  9. use Drupal\Core\Url;
  10. /**
  11. * Implements hook_schema().
  12. */
  13. function search_api_schema() {
  14. $schema['search_api_item'] = [
  15. 'description' => 'Stores the items which should be indexed for each index, and their state.',
  16. 'fields' => [
  17. 'index_id' => [
  18. 'description' => 'The ID of the index this item belongs to',
  19. 'type' => 'varchar',
  20. 'length' => 50,
  21. 'not null' => TRUE,
  22. ],
  23. 'datasource' => [
  24. 'description' => 'The plugin ID of the datasource this item belongs to',
  25. 'type' => 'varchar',
  26. 'length' => 50,
  27. 'not null' => TRUE,
  28. ],
  29. 'item_id' => [
  30. 'description' => 'The unique identifier of this item',
  31. 'type' => 'varchar',
  32. 'length' => 150,
  33. 'not null' => TRUE,
  34. ],
  35. 'changed' => [
  36. 'description' => 'A timestamp indicating when the item was last changed',
  37. 'type' => 'int',
  38. 'unsigned' => TRUE,
  39. 'not null' => TRUE,
  40. ],
  41. 'status' => [
  42. 'description' => 'Boolean indicating the reindexation status, "1" when we need to reindex, "0" otherwise',
  43. 'type' => 'int',
  44. 'not null' => TRUE,
  45. ],
  46. ],
  47. 'indexes' => [
  48. 'indexing' => ['index_id', 'status', 'changed', 'item_id'],
  49. ],
  50. 'primary key' => ['index_id', 'item_id'],
  51. ];
  52. return $schema;
  53. }
  54. /**
  55. * Implements hook_uninstall().
  56. */
  57. function search_api_uninstall() {
  58. \Drupal::state()->delete('search_api_use_tracking_batch');
  59. foreach (\Drupal::configFactory()->listAll('search_api.index.') as $index_id) {
  60. \Drupal::state()->delete("search_api.index.$index_id.has_reindexed");
  61. }
  62. }
  63. /**
  64. * Implements hook_requirements().
  65. */
  66. function search_api_requirements($phase) {
  67. if ($phase == 'runtime') {
  68. $requirements = [];
  69. $message = _search_api_search_module_warning();
  70. if ($message) {
  71. $requirements += [
  72. 'search_api_core_search' => [
  73. 'title' => t('Search API'),
  74. 'value' => $message,
  75. 'severity' => REQUIREMENT_WARNING,
  76. ],
  77. ];
  78. }
  79. /** @var \Drupal\search_api\ServerInterface[] $servers */
  80. $servers = Server::loadMultiple();
  81. $unavailable_servers = [];
  82. foreach ($servers as $server) {
  83. if ($server->status() && !$server->isAvailable()) {
  84. $unavailable_servers[] = $server->label();
  85. }
  86. }
  87. if (!empty($unavailable_servers)) {
  88. $requirements += [
  89. 'search_api_server_unavailable' => [
  90. 'title' => t('Search API'),
  91. 'value' => \Drupal::translation()->formatPlural(
  92. count($unavailable_servers),
  93. 'The search server "@servers" is currently not available',
  94. 'The following search servers are not available: @servers',
  95. ['@servers' => implode(', ', $unavailable_servers)]
  96. ),
  97. 'severity' => REQUIREMENT_ERROR
  98. ]
  99. ];
  100. }
  101. $pending_tasks = \Drupal::getContainer()
  102. ->get('search_api.task_manager')
  103. ->getTasksCount();
  104. if ($pending_tasks) {
  105. $args['@link'] = '';
  106. $url = Url::fromRoute('search_api.execute_tasks');
  107. if ($url->access()) {
  108. $link = new Link(t('Execute now'), $url);
  109. $link = $link->toString();
  110. $args['@link'] = $link;
  111. $args['@link'] = new FormattableMarkup(' (@link)', $args);
  112. }
  113. $requirements['search_api_pending_tasks'] = [
  114. 'title' => t('Search API'),
  115. 'value' => \Drupal::translation()->formatPlural(
  116. $pending_tasks,
  117. 'There is @count pending Search API task. @link',
  118. 'There are @count pending Search API tasks. @link',
  119. $args
  120. ),
  121. 'severity' => REQUIREMENT_WARNING,
  122. ];
  123. }
  124. return $requirements;
  125. }
  126. return [];
  127. }
  128. /**
  129. * Adapts index config schema to remove an unnecessary layer for plugins.
  130. */
  131. function search_api_update_8101() {
  132. // This update function updates search indexes for the change from
  133. // https://www.drupal.org/node/2656052.
  134. $config_factory = \Drupal::configFactory();
  135. $plugin_types = [
  136. 'processor',
  137. 'datasource',
  138. 'tracker',
  139. ];
  140. foreach ($config_factory->listAll('search_api.index.') as $index_id) {
  141. $index = $config_factory->getEditable($index_id);
  142. $changed = FALSE;
  143. foreach ($plugin_types as $plugin_type) {
  144. $property = $plugin_type . '_settings';
  145. $plugins = $index->get($property);
  146. foreach ($plugins as $id => $config) {
  147. if (isset($config['plugin_id']) && isset($config['settings'])) {
  148. $changed = TRUE;
  149. $plugins[$id] = $config['settings'];
  150. }
  151. }
  152. $index->set($property, $plugins);
  153. }
  154. if ($changed) {
  155. // Mark the resulting configuration as trusted data. This avoids issues
  156. // with future schema changes.
  157. $index->save(TRUE);
  158. }
  159. }
  160. return t('Index config schema updated.');
  161. }
  162. /**
  163. * Removes unsupported cache plugins from Search API views.
  164. */
  165. function search_api_update_8102() {
  166. $config_factory = \Drupal::configFactory();
  167. $changed = [];
  168. foreach ($config_factory->listAll('views.view.') as $view_config_name) {
  169. $view = $config_factory->getEditable($view_config_name);
  170. $displays = $view->get('display');
  171. if ($displays['default']['display_options']['query']['type'] === 'search_api_query') {
  172. $change = FALSE;
  173. foreach ($displays as $id => $display) {
  174. if (!empty($display['display_options']['cache']['type']) && in_array($display['display_options']['cache']['type'], ['tag', 'time'])
  175. ) {
  176. $displays[$id]['display_options']['cache']['type'] = 'none';
  177. $change = TRUE;
  178. }
  179. }
  180. if ($change) {
  181. $view->set('display', $displays);
  182. // Mark the resulting configuration as trusted data. This avoids issues
  183. // with future schema changes.
  184. $view->save(TRUE);
  185. $changed[] = $view->get('id');
  186. }
  187. }
  188. }
  189. if (!empty($changed)) {
  190. return \Drupal::translation()->translate('Removed incompatible cache options for the following Search API-based views: @ids', ['@ids' => implode(', ', array_unique($changed))]);
  191. }
  192. return NULL;
  193. }
  194. /**
  195. * Switches from the old "Node status" to the new "Entity status" processor.
  196. */
  197. function search_api_update_8103() {
  198. // This update function updates search indexes for the change from
  199. // https://www.drupal.org/node/2491175.
  200. $config_factory = \Drupal::configFactory();
  201. foreach ($config_factory->listAll('search_api.index.') as $index_id) {
  202. $index = $config_factory->getEditable($index_id);
  203. $processors = $index->get('processor_settings');
  204. if (isset($processors['node_status'])) {
  205. $processors['entity_status'] = $processors['node_status'];
  206. unset($processors['node_status']);
  207. $index->set('processor_settings', $processors);
  208. // Mark the resulting configuration as trusted data. This avoids issues
  209. // with future schema changes.
  210. $index->save(TRUE);
  211. }
  212. }
  213. // Clear the processor plugin cache so that if anything else indirectly tries
  214. // to update Search API-related configuration, the plugin helper gets the most
  215. // up-to-date plugin definitions.
  216. \Drupal::getContainer()
  217. ->get('plugin.manager.search_api.processor')
  218. ->clearCachedDefinitions();
  219. return t('Switched from old "Node status" to new "Entity status" processor.');
  220. }
  221. /**
  222. * Update Views to use the time-based cache plugin for Search API.
  223. */
  224. function search_api_update_8104() {
  225. $config_factory = \Drupal::configFactory();
  226. $changed = [];
  227. foreach ($config_factory->listAll('views.view.') as $view_config_name) {
  228. $view = $config_factory->getEditable($view_config_name);
  229. $displays = $view->get('display');
  230. $updated = FALSE;
  231. foreach ($displays as $id => $display) {
  232. if (!empty($display['display_options']['cache']['type']) && $display['display_options']['cache']['type'] === 'search_api') {
  233. $displays[$id]['display_options']['cache']['type'] = 'search_api_time';
  234. $updated = TRUE;
  235. }
  236. }
  237. if ($updated) {
  238. $view->set('display', $displays);
  239. // Mark the resulting configuration as trusted data. This avoids issues
  240. // with future schema changes.
  241. $view->save(TRUE);
  242. $changed[] = $view->get('id');
  243. }
  244. }
  245. if (!empty($changed)) {
  246. return \Drupal::translation()->translate('The following views have been updated to use the time-based cache plugin: @ids', ['@ids' => implode(', ', array_unique($changed))]);
  247. }
  248. return NULL;
  249. }