search_api.install 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. <?php
  2. /**
  3. * @file
  4. * Install, update and uninstall functions for the Search API module.
  5. */
  6. /**
  7. * Implements hook_schema().
  8. */
  9. function search_api_schema() {
  10. $schema['search_api_server'] = array(
  11. 'description' => 'Stores all search servers created through the Search API.',
  12. 'fields' => array(
  13. 'id' => array(
  14. 'description' => 'The primary identifier for a server.',
  15. 'type' => 'serial',
  16. 'unsigned' => TRUE,
  17. 'not null' => TRUE,
  18. ),
  19. 'name' => array(
  20. 'description' => 'The displayed name for a server.',
  21. 'type' => 'varchar',
  22. 'length' => 50,
  23. 'not null' => TRUE,
  24. ),
  25. 'machine_name' => array(
  26. 'description' => 'The machine name for a server.',
  27. 'type' => 'varchar',
  28. 'length' => 50,
  29. 'not null' => TRUE,
  30. ),
  31. 'description' => array(
  32. 'description' => 'The displayed description for a server.',
  33. 'type' => 'text',
  34. 'not null' => FALSE,
  35. ),
  36. 'class' => array(
  37. 'description' => 'The id of the service class to use for this server.',
  38. 'type' => 'varchar',
  39. 'length' => 50,
  40. 'not null' => TRUE,
  41. ),
  42. 'options' => array(
  43. 'description' => 'The options used to configure the service object.',
  44. 'type' => 'text',
  45. 'size' => 'medium',
  46. 'serialize' => TRUE,
  47. 'not null' => TRUE,
  48. ),
  49. 'enabled' => array(
  50. 'description' => 'A flag indicating whether the server is enabled.',
  51. 'type' => 'int',
  52. 'size' => 'tiny',
  53. 'not null' => TRUE,
  54. 'default' => 1,
  55. ),
  56. 'status' => array(
  57. 'description' => 'The exportable status of the entity.',
  58. 'type' => 'int',
  59. 'not null' => TRUE,
  60. 'default' => 0x01,
  61. 'size' => 'tiny',
  62. ),
  63. 'module' => array(
  64. 'description' => 'The name of the providing module if the entity has been defined in code.',
  65. 'type' => 'varchar',
  66. 'length' => 255,
  67. 'not null' => FALSE,
  68. ),
  69. ),
  70. 'indexes' => array(
  71. 'enabled' => array('enabled'),
  72. ),
  73. 'unique keys' => array(
  74. 'machine_name' => array('machine_name'),
  75. ),
  76. 'primary key' => array('id'),
  77. );
  78. $schema['search_api_index'] = array(
  79. 'description' => 'Stores all search indexes on a {search_api_server}.',
  80. 'fields' => array(
  81. 'id' => array(
  82. 'description' => 'An integer identifying the index.',
  83. 'type' => 'serial',
  84. 'unsigned' => TRUE,
  85. 'not null' => TRUE,
  86. ),
  87. 'name' => array(
  88. 'description' => 'A name to be displayed for the index.',
  89. 'type' => 'varchar',
  90. 'length' => 50,
  91. 'not null' => TRUE,
  92. ),
  93. 'machine_name' => array(
  94. 'description' => 'The machine name of the index.',
  95. 'type' => 'varchar',
  96. 'length' => 50,
  97. 'not null' => TRUE,
  98. ),
  99. 'description' => array(
  100. 'description' => "A string describing the index' use to users.",
  101. 'type' => 'text',
  102. 'not null' => FALSE,
  103. ),
  104. 'server' => array(
  105. 'description' => 'The {search_api_server}.machine_name with which data should be indexed.',
  106. 'type' => 'varchar',
  107. 'length' => 50,
  108. 'not null' => FALSE,
  109. ),
  110. 'item_type' => array(
  111. 'description' => 'The type of items stored in this index.',
  112. 'type' => 'varchar',
  113. 'length' => 50,
  114. 'not null' => TRUE,
  115. ),
  116. 'options' => array(
  117. 'description' => 'An array of additional arguments configuring this index.',
  118. 'type' => 'text',
  119. 'size' => 'medium',
  120. 'serialize' => TRUE,
  121. 'not null' => TRUE,
  122. ),
  123. 'enabled' => array(
  124. 'description' => 'A flag indicating whether this index is enabled.',
  125. 'type' => 'int',
  126. 'size' => 'tiny',
  127. 'not null' => TRUE,
  128. 'default' => 1,
  129. ),
  130. 'read_only' => array(
  131. 'description' => 'A flag indicating whether to write to this index.',
  132. 'type' => 'int',
  133. 'size' => 'tiny',
  134. 'not null' => TRUE,
  135. 'default' => 0,
  136. ),
  137. 'status' => array(
  138. 'description' => 'The exportable status of the entity.',
  139. 'type' => 'int',
  140. 'not null' => TRUE,
  141. 'default' => 0x01,
  142. 'size' => 'tiny',
  143. ),
  144. 'module' => array(
  145. 'description' => 'The name of the providing module if the entity has been defined in code.',
  146. 'type' => 'varchar',
  147. 'length' => 255,
  148. 'not null' => FALSE,
  149. ),
  150. ),
  151. 'indexes' => array(
  152. 'item_type' => array('item_type'),
  153. 'server' => array('server'),
  154. 'enabled' => array('enabled'),
  155. ),
  156. 'unique keys' => array(
  157. 'machine_name' => array('machine_name'),
  158. ),
  159. 'primary key' => array('id'),
  160. );
  161. $schema['search_api_item'] = array(
  162. 'description' => 'Stores the items which should be indexed for each index, and their status.',
  163. 'fields' => array(
  164. 'item_id' => array(
  165. 'description' => "The item's entity id (e.g. {node}.nid for nodes).",
  166. 'type' => 'int',
  167. 'unsigned' => TRUE,
  168. 'not null' => TRUE,
  169. ),
  170. 'index_id' => array(
  171. 'description' => 'The {search_api_index}.id this item belongs to.',
  172. 'type' => 'int',
  173. 'unsigned' => TRUE,
  174. 'not null' => TRUE,
  175. ),
  176. 'changed' => array(
  177. 'description' => 'Either a flag or a timestamp to indicate if or when the item was changed since it was last indexed.',
  178. 'type' => 'int',
  179. 'size' => 'big',
  180. 'not null' => TRUE,
  181. 'default' => 1,
  182. ),
  183. ),
  184. 'indexes' => array(
  185. 'indexing' => array('index_id', 'changed'),
  186. ),
  187. 'primary key' => array('item_id', 'index_id'),
  188. );
  189. $schema['search_api_task'] = array(
  190. 'description' => 'Stores pending tasks for servers.',
  191. 'fields' => array(
  192. 'id' => array(
  193. 'description' => 'An integer identifying this task.',
  194. 'type' => 'serial',
  195. 'unsigned' => TRUE,
  196. 'not null' => TRUE,
  197. ),
  198. 'server_id' => array(
  199. 'description' => 'The {search_api_server}.machine_name for which this task should be executed.',
  200. 'type' => 'varchar',
  201. 'length' => 50,
  202. 'not null' => TRUE,
  203. ),
  204. 'type' => array(
  205. 'description' => 'A keyword identifying the type of task that should be executed.',
  206. 'type' => 'varchar',
  207. 'length' => 50,
  208. 'not null' => TRUE,
  209. ),
  210. 'index_id' => array(
  211. 'description' => 'The {search_api_index}.machine_name to which this task pertains, if applicable for this type.',
  212. 'type' => 'varchar',
  213. 'length' => 50,
  214. 'not null' => FALSE,
  215. ),
  216. 'data' => array(
  217. 'description' => 'Some data needed for the task, might be optional depending on the type.',
  218. 'type' => 'text',
  219. 'size' => 'medium',
  220. 'serialize' => TRUE,
  221. 'not null' => FALSE,
  222. ),
  223. ),
  224. 'indexes' => array(
  225. 'server' => array('server_id'),
  226. ),
  227. 'primary key' => array('id'),
  228. );
  229. return $schema;
  230. }
  231. /**
  232. * Implements hook_install().
  233. *
  234. * Creates a default node index if the module is installed manually.
  235. */
  236. function search_api_install() {
  237. // In case the module is installed via an installation profile, a batch is
  238. // active and we skip that.
  239. if (batch_get()) {
  240. return;
  241. }
  242. $name = t('Default node index');
  243. $values = array(
  244. 'name' => $name,
  245. 'machine_name' => preg_replace('/[^a-z0-9]+/', '_', drupal_strtolower($name)),
  246. 'description' => t('An automatically created search index for indexing node data. Might be configured to specific needs.'),
  247. 'server' => NULL,
  248. 'item_type' => 'node',
  249. 'options' => array(
  250. 'index_directly' => 1,
  251. 'cron_limit' => '50',
  252. 'data_alter_callbacks' => array(
  253. 'search_api_alter_node_access' => array(
  254. 'status' => 1,
  255. 'weight' => '0',
  256. 'settings' => array(),
  257. ),
  258. ),
  259. 'processors' => array(
  260. 'search_api_case_ignore' => array(
  261. 'status' => 1,
  262. 'weight' => '0',
  263. 'settings' => array(
  264. 'strings' => 0,
  265. ),
  266. ),
  267. 'search_api_html_filter' => array(
  268. 'status' => 1,
  269. 'weight' => '10',
  270. 'settings' => array(
  271. 'title' => 0,
  272. 'alt' => 1,
  273. 'tags' => "h1 = 5\n" .
  274. "h2 = 3\n" .
  275. "h3 = 2\n" .
  276. "strong = 2\n" .
  277. "b = 2\n" .
  278. "em = 1.5\n" .
  279. "u = 1.5",
  280. ),
  281. ),
  282. 'search_api_tokenizer' => array(
  283. 'status' => 1,
  284. 'weight' => '20',
  285. 'settings' => array(
  286. 'spaces' => '[^\\p{L}\\p{N}]',
  287. 'ignorable' => '[-]',
  288. ),
  289. ),
  290. ),
  291. 'fields' => array(
  292. 'type' => array(
  293. 'type' => 'string',
  294. ),
  295. 'title' => array(
  296. 'type' => 'text',
  297. 'boost' => '5.0',
  298. ),
  299. 'promote' => array(
  300. 'type' => 'boolean',
  301. ),
  302. 'sticky' => array(
  303. 'type' => 'boolean',
  304. ),
  305. 'created' => array(
  306. 'type' => 'date',
  307. ),
  308. 'changed' => array(
  309. 'type' => 'date',
  310. ),
  311. 'author' => array(
  312. 'type' => 'integer',
  313. 'entity_type' => 'user',
  314. ),
  315. 'comment_count' => array(
  316. 'type' => 'integer',
  317. ),
  318. 'search_api_language' => array(
  319. 'type' => 'string',
  320. ),
  321. 'body:value' => array(
  322. 'type' => 'text',
  323. ),
  324. ),
  325. ),
  326. );
  327. search_api_index_insert($values);
  328. drupal_set_message('The Search API module was installed. A new default node index was created.');
  329. }
  330. /**
  331. * Implements hook_enable().
  332. *
  333. * Mark all items as "dirty", since we can't know whether they are.
  334. */
  335. function search_api_enable() {
  336. $types = array();
  337. foreach (search_api_index_load_multiple(FALSE) as $index) {
  338. if ($index->enabled) {
  339. $types[$index->item_type][] = $index;
  340. }
  341. }
  342. foreach ($types as $type => $indexes) {
  343. try {
  344. $controller = search_api_get_datasource_controller($type);
  345. $controller->startTracking($indexes);
  346. }
  347. catch (SearchApiException $e) {
  348. watchdog_exception('search_api', $e);
  349. }
  350. }
  351. }
  352. /**
  353. * Implements hook_disable().
  354. */
  355. function search_api_disable() {
  356. $types = array();
  357. foreach (search_api_index_load_multiple(FALSE) as $index) {
  358. $types[$index->item_type][] = $index;
  359. }
  360. foreach ($types as $type => $indexes) {
  361. try {
  362. $controller = search_api_get_datasource_controller($type);
  363. $controller->stopTracking($indexes);
  364. }
  365. catch (SearchApiException $e) {
  366. // Modules defining entity or item types might have been disabled. Ignore.
  367. }
  368. }
  369. }
  370. /**
  371. * Implements hook_uninstall().
  372. */
  373. function search_api_uninstall() {
  374. variable_del('search_api_index_worker_callback_runtime');
  375. }
  376. /**
  377. * Update function that adds the machine names for servers and indexes.
  378. */
  379. function search_api_update_7101() {
  380. $tx = db_transaction();
  381. try {
  382. // Servers
  383. $spec = array(
  384. 'description' => 'The machine name for a server.',
  385. 'type' => 'varchar',
  386. 'length' => 50,
  387. 'not null' => TRUE,
  388. 'default' => '',
  389. );
  390. db_add_field('search_api_server', 'machine_name', $spec);
  391. $names = array();
  392. $servers = db_select('search_api_server', 's')
  393. ->fields('s')
  394. ->execute();
  395. foreach ($servers as $server) {
  396. $base = $name = drupal_strtolower(preg_replace('/[^a-z0-9]+/i', '_', $server->name));
  397. $i = 0;
  398. while (isset($names[$name])) {
  399. $name = $base . '_' . ++$i;
  400. }
  401. $names[$name] = TRUE;
  402. db_update('search_api_server')
  403. ->fields(array('machine_name' => $name))
  404. ->condition('id', $server->id)
  405. ->execute();
  406. }
  407. db_add_unique_key('search_api_server', 'machine_name', array('machine_name'));
  408. //Indexes
  409. $spec = array(
  410. 'description' => 'The machine name of the index.',
  411. 'type' => 'varchar',
  412. 'length' => 50,
  413. 'not null' => TRUE,
  414. 'default' => '',
  415. );
  416. db_add_field('search_api_index', 'machine_name', $spec);
  417. $names = array();
  418. $indexes = db_select('search_api_index', 'i')
  419. ->fields('i')
  420. ->execute();
  421. foreach ($indexes as $index) {
  422. $base = $name = drupal_strtolower(preg_replace('/[^a-z0-9]+/i', '_', $index->name));
  423. $i = 0;
  424. while (isset($names[$name])) {
  425. $name = $base . '_' . ++$i;
  426. }
  427. $names[$name] = TRUE;
  428. db_update('search_api_index')
  429. ->fields(array('machine_name' => $name))
  430. ->condition('id', $index->id)
  431. ->execute();
  432. }
  433. db_add_unique_key('search_api_index', 'machine_name', array('machine_name'));
  434. }
  435. catch (Exception $e) {
  436. $tx->rollback();
  437. try {
  438. db_drop_field('search_api_server', 'machine_name');
  439. db_drop_field('search_api_index', 'machine_name');
  440. }
  441. catch (Exception $e1) {
  442. // Ignore.
  443. }
  444. throw new DrupalUpdateException(t('An exception occurred during the update: @msg.', array('@msg' => $e->getMessage())));
  445. }
  446. }
  447. /**
  448. * Update replacing IDs with machine names for foreign keys.
  449. * {search_api_index}.server and {search_api_item}.index_id are altered.
  450. */
  451. function search_api_update_7102() {
  452. // Update of search_api_index:
  453. $indexes = array();
  454. $select = db_select('search_api_index', 'i')->fields('i');
  455. foreach ($select->execute() as $index) {
  456. $indexes[$index->id] = $index;
  457. }
  458. $servers = db_select('search_api_server', 's')->fields('s', array('id', 'machine_name'))->execute()->fetchAllKeyed();
  459. db_drop_index('search_api_index', 'server');
  460. db_drop_field('search_api_index', 'server');
  461. $spec = array(
  462. 'description' => 'The {search_api_server}.machine_name with which data should be indexed.',
  463. 'type' => 'varchar',
  464. 'length' => 50,
  465. 'not null' => FALSE,
  466. );
  467. db_add_field('search_api_index', 'server', $spec);
  468. foreach ($indexes as $index) {
  469. db_update('search_api_index')
  470. ->fields(array('server' => $servers[$index->server]))
  471. ->condition('id', $index->id)
  472. ->execute();
  473. }
  474. db_add_index('search_api_index', 'server', array('server'));
  475. // Update of search_api_item:
  476. db_drop_index('search_api_item', 'indexing');
  477. db_drop_primary_key('search_api_item');
  478. $spec = array(
  479. 'description' => 'The {search_api_index}.machine_name this item belongs to.',
  480. 'type' => 'varchar',
  481. 'length' => 50,
  482. 'not null' => TRUE,
  483. );
  484. $keys_new = array(
  485. 'indexes' => array(
  486. 'indexing' => array('index_id', 'changed'),
  487. ),
  488. 'primary key' => array('item_id', 'index_id'),
  489. );
  490. db_change_field('search_api_item', 'index_id', 'index_id', $spec, $keys_new);
  491. foreach ($indexes as $index) {
  492. // We explicitly forbid numeric machine names, therefore we don't have to
  493. // worry about conflicts here.
  494. db_update('search_api_item')
  495. ->fields(array(
  496. 'index_id' => $index->machine_name,
  497. ))
  498. ->condition('index_id', $index->id)
  499. ->execute();
  500. }
  501. }
  502. /**
  503. * Add the database fields newly required for entities by the Entity API.
  504. */
  505. function search_api_update_7103() {
  506. if (!function_exists('entity_exportable_schema_fields')) {
  507. throw new DrupalUpdateException(t('Please update the Entity API module first.'));
  508. }
  509. foreach (array('search_api_server', 'search_api_index') as $table) {
  510. foreach (entity_exportable_schema_fields() as $field => $spec) {
  511. db_add_field($table, $field, $spec);
  512. }
  513. }
  514. }
  515. /**
  516. * Initialize the "Fields to run on" settings for processors.
  517. */
  518. function search_api_update_7107() {
  519. $rows = db_select('search_api_index', 'i')
  520. ->fields('i', array('id', 'options'))
  521. ->execute()
  522. ->fetchAllKeyed();
  523. foreach ($rows as $id => $options) {
  524. $opt = unserialize($options);
  525. $processors = &$opt['processors'];
  526. // Only update our own processors, don't mess with others.
  527. $check_processors = array(
  528. 'search_api_case_ignore' => 1,
  529. 'search_api_html_filter' => 1,
  530. 'search_api_tokenizer' => 1,
  531. );
  532. foreach (array_intersect_key($processors, $check_processors) as $name => $info) {
  533. $types = array('text');
  534. if (!empty($info['settings']['strings'])) {
  535. $types[] = 'string';
  536. unset($processors[$name]['settings']['strings']);
  537. }
  538. foreach ($opt['fields'] as $field => $info) {
  539. if ($info['indexed'] && search_api_is_text_type($info['type'], $types)) {
  540. $processors[$name]['settings']['fields'][$field] = $field;
  541. }
  542. }
  543. }
  544. $opt = serialize($opt);
  545. if ($opt != $options) {
  546. db_update('search_api_index')
  547. ->fields(array(
  548. 'options' => $opt,
  549. ))
  550. ->condition('id', $id)
  551. ->execute();
  552. }
  553. }
  554. }
  555. /**
  556. * Change {search_api_item}.index_id back to the index' numeric ID.
  557. */
  558. function search_api_update_7104() {
  559. $select = db_select('search_api_index', 'i')->fields('i');
  560. foreach ($select->execute() as $index) {
  561. // We explicitly forbid numeric machine names, therefore we don't have to
  562. // worry about conflicts here.
  563. db_update('search_api_item')
  564. ->fields(array(
  565. 'index_id' => $index->id,
  566. ))
  567. ->condition('index_id', $index->machine_name)
  568. ->execute();
  569. }
  570. // Update primary key and index.
  571. db_drop_index('search_api_item', 'indexing');
  572. db_drop_primary_key('search_api_item');
  573. $spec = array(
  574. 'description' => 'The {search_api_index}.id this item belongs to.',
  575. 'type' => 'int',
  576. 'unsigned' => TRUE,
  577. 'not null' => TRUE,
  578. );
  579. $keys_new = array(
  580. 'indexes' => array(
  581. 'indexing' => array('index_id', 'changed'),
  582. ),
  583. 'primary key' => array('item_id', 'index_id'),
  584. );
  585. db_change_field('search_api_item', 'index_id', 'index_id', $spec, $keys_new);
  586. }
  587. /**
  588. * Remove all empty aggregated fields for the search_api_alter_add_fulltext data
  589. * alterations.
  590. */
  591. function search_api_update_7105() {
  592. $rows = db_select('search_api_index', 'i')
  593. ->fields('i', array('id', 'options'))
  594. ->execute()
  595. ->fetchAllKeyed();
  596. foreach ($rows as $id => $options) {
  597. $opt = unserialize($options);
  598. if (isset($opt['data_alter_callbacks']['search_api_alter_add_fulltext']['settings']['fields'])) {
  599. foreach ($opt['data_alter_callbacks']['search_api_alter_add_fulltext']['settings']['fields'] as $name => $field) {
  600. if (empty($field['name']) || empty($field['fields'])) {
  601. unset($opt['data_alter_callbacks']['search_api_alter_add_fulltext']['settings']['fields'][$name]);
  602. }
  603. }
  604. }
  605. $opt = serialize($opt);
  606. if ($opt != $options) {
  607. db_update('search_api_index')
  608. ->fields(array(
  609. 'options' => $opt,
  610. ))
  611. ->condition('id', $id)
  612. ->execute();
  613. }
  614. }
  615. }
  616. /**
  617. * Update the settings for the "Aggregated fields" data alteration.
  618. */
  619. function search_api_update_7106() {
  620. $rows = db_select('search_api_index', 'i')
  621. ->fields('i')
  622. ->execute()
  623. ->fetchAll();
  624. foreach ($rows as $row) {
  625. $opt = unserialize($row->options);
  626. $callbacks = &$opt['data_alter_callbacks'];
  627. if (isset($callbacks['search_api_alter_add_fulltext'])) {
  628. $callbacks['search_api_alter_add_aggregation'] = $callbacks['search_api_alter_add_fulltext'];
  629. unset($callbacks['search_api_alter_add_fulltext']);
  630. if (!empty($callbacks['search_api_alter_add_aggregation']['settings']['fields'])) {
  631. foreach ($callbacks['search_api_alter_add_aggregation']['settings']['fields'] as &$info) {
  632. if (!isset($info['type'])) {
  633. $info['type'] = 'fulltext';
  634. }
  635. }
  636. }
  637. }
  638. $opt = serialize($opt);
  639. if ($opt != $row->options) {
  640. // Mark the entity as overridden, in case it has been defined in code
  641. // only.
  642. $row->status |= 0x01;
  643. db_update('search_api_index')
  644. ->fields(array(
  645. 'options' => $opt,
  646. 'status' => $row->status,
  647. ))
  648. ->condition('id', $row->id)
  649. ->execute();
  650. }
  651. }
  652. }
  653. /**
  654. * Add "read only" property to Search API index entities.
  655. */
  656. function search_api_update_7108() {
  657. $db_field = array(
  658. 'description' => 'A flag indicating whether to write to this index.',
  659. 'type' => 'int',
  660. 'size' => 'tiny',
  661. 'not null' => TRUE,
  662. 'default' => 0,
  663. );
  664. db_add_field('search_api_index', 'read_only', $db_field);
  665. return t('Added a "read only" property to index entities.');
  666. }
  667. /**
  668. * Clear entity info cache, as entity controller classes hae changed.
  669. */
  670. function search_api_update_7109() {
  671. cache_clear_all('entity_info:', 'cache', TRUE);
  672. }
  673. /**
  674. * Rename the "entity_type" field to "item_type" in the {search_api_index} table.
  675. */
  676. function search_api_update_7110() {
  677. $table = 'search_api_index';
  678. // This index isn't used anymore.
  679. db_drop_index($table, 'entity_type');
  680. // Rename the "item_type" field (and change the description).
  681. $item_type = array(
  682. 'description' => 'The type of items stored in this index.',
  683. 'type' => 'varchar',
  684. 'length' => 50,
  685. 'not null' => TRUE,
  686. );
  687. // Also add the new "item_type" index, while we're at it.
  688. $keys_new['indexes']['item_type'] = array('item_type');
  689. db_change_field($table, 'entity_type', 'item_type', $item_type, $keys_new);
  690. // Mark all indexes in code as "OVERRIDDEN".
  691. db_update($table)
  692. ->fields(array(
  693. 'status' => 0x03,
  694. ))
  695. ->condition('status', 0x02)
  696. ->execute();
  697. // Clear entity info caches.
  698. cache_clear_all('*', 'cache', TRUE);
  699. }
  700. /**
  701. * Change the definition of the {search_api_item}.changed field.
  702. */
  703. function search_api_update_7111() {
  704. $spec = array(
  705. 'description' => 'Either a flag or a timestamp to indicate if or when the item was changed since it was last indexed.',
  706. 'type' => 'int',
  707. 'size' => 'big',
  708. 'not null' => TRUE,
  709. 'default' => 1,
  710. );
  711. db_change_field('search_api_item', 'changed', 'changed', $spec);
  712. }
  713. /**
  714. * Changes the size of the {search_api_index}.options and {search_api_server}.options fields to "medium".
  715. */
  716. function search_api_update_7112() {
  717. $spec = array(
  718. 'description' => 'The options used to configure the service object.',
  719. 'type' => 'text',
  720. 'size' => 'medium',
  721. 'serialize' => TRUE,
  722. 'not null' => TRUE,
  723. );
  724. db_change_field('search_api_server', 'options', 'options', $spec);
  725. $spec = array(
  726. 'description' => 'An array of additional arguments configuring this index.',
  727. 'type' => 'text',
  728. 'size' => 'medium',
  729. 'serialize' => TRUE,
  730. 'not null' => TRUE,
  731. );
  732. db_change_field('search_api_index', 'options', 'options', $spec);
  733. }
  734. /**
  735. * Removes superfluous data from the stored index options.
  736. */
  737. function search_api_update_7113() {
  738. $indexes = db_select('search_api_index', 'i')
  739. ->fields('i')
  740. ->execute();
  741. foreach ($indexes as $index) {
  742. $options = unserialize($index->options);
  743. // Weed out fields settings.
  744. if (!empty($options['fields'])) {
  745. foreach ($options['fields'] as $key => $field) {
  746. if (isset($field['indexed']) && !$field['indexed']) {
  747. unset($options['fields'][$key]);
  748. continue;
  749. }
  750. unset($options['fields'][$key]['name'], $options['fields'][$key]['indexed']);
  751. if (isset($field['boost']) && $field['boost'] == '1.0') {
  752. unset($options['fields'][$key]['boost']);
  753. }
  754. }
  755. }
  756. // Weed out processor settings.
  757. if (!empty($options['processors'])) {
  758. // Only weed out settings for our own processors.
  759. $processors = array('search_api_case_ignore', 'search_api_html_filter', 'search_api_tokenizer', 'search_api_stopwords');
  760. foreach ($processors as $key) {
  761. if (empty($options['processors'][$key])) {
  762. continue;
  763. }
  764. $processor = $options['processors'][$key];
  765. if (empty($processor['settings']['fields'])) {
  766. continue;
  767. }
  768. $fields = array_filter($processor['settings']['fields']);
  769. if ($fields) {
  770. $fields = array_combine($fields, array_fill(0, count($fields), TRUE));
  771. }
  772. $options['processors'][$key]['settings']['fields'] = $fields;
  773. }
  774. }
  775. // Weed out settings for the „Aggregated fields“ data alteration.
  776. if (!empty($options['data_alter_callbacks']['search_api_alter_add_aggregation']['settings']['fields'])) {
  777. unset($options['data_alter_callbacks']['search_api_alter_add_aggregation']['settings']['actions']);
  778. $aggregated_fields = &$options['data_alter_callbacks']['search_api_alter_add_aggregation']['settings']['fields'];
  779. foreach ($aggregated_fields as $key => $field) {
  780. unset($aggregated_fields[$key]['actions']);
  781. if (!empty($field['fields'])) {
  782. $aggregated_fields[$key]['fields'] = array_values(array_filter($field['fields']));
  783. }
  784. }
  785. }
  786. $options = serialize($options);
  787. if ($options != $index->options) {
  788. // Mark the entity as overridden, in case it has been defined in code
  789. // only.
  790. $index->status |= 0x01;
  791. db_update('search_api_index')
  792. ->fields(array(
  793. 'options' => $options,
  794. 'status' => $index->status,
  795. ))
  796. ->condition('id', $index->id)
  797. ->execute();
  798. }
  799. }
  800. }
  801. /**
  802. * Sanitize watchdog messages.
  803. */
  804. function search_api_update_7114() {
  805. if (db_table_exists('watchdog')) {
  806. try {
  807. $entries = db_select('watchdog', 'w')
  808. ->fields('w', array('wid', 'message'))
  809. ->condition('type', 'search_api')
  810. ->execute();
  811. foreach ($entries as $entry) {
  812. db_update('watchdog')
  813. ->fields(array(
  814. 'message' => check_plain($entry->message),
  815. ))
  816. ->condition('wid', $entry->wid)
  817. ->execute();
  818. }
  819. }
  820. catch (Exception $e) {
  821. throw new DrupalUpdateException(t('An exception occurred during the update: @msg.', array('@msg' => $e->getMessage())));
  822. }
  823. }
  824. }
  825. /**
  826. * Switch to indexing without the use of a cron queue.
  827. */
  828. function search_api_update_7115() {
  829. variable_del('search_api_batch_per_cron');
  830. DrupalQueue::get('search_api_indexing_queue')->deleteQueue();
  831. db_update('search_api_item')
  832. ->fields(array(
  833. 'changed' => 1,
  834. ))
  835. ->condition('changed', 0, '<')
  836. ->execute();
  837. }
  838. /**
  839. * Transfers the tasks for disabled servers to a separate database table.
  840. */
  841. function search_api_update_7116() {
  842. // Create table.
  843. $table = array(
  844. 'description' => 'Stores pending tasks for servers.',
  845. 'fields' => array(
  846. 'id' => array(
  847. 'description' => 'An integer identifying this task.',
  848. 'type' => 'serial',
  849. 'unsigned' => TRUE,
  850. 'not null' => TRUE,
  851. ),
  852. 'server_id' => array(
  853. 'description' => 'The {search_api_server}.machine_name for which this task should be executed.',
  854. 'type' => 'varchar',
  855. 'length' => 50,
  856. 'not null' => TRUE,
  857. ),
  858. 'type' => array(
  859. 'description' => 'A keyword identifying the type of task that should be executed.',
  860. 'type' => 'varchar',
  861. 'length' => 50,
  862. 'not null' => TRUE,
  863. ),
  864. 'index_id' => array(
  865. 'description' => 'The {search_api_index}.machine_name to which this task pertains, if applicable for this type.',
  866. 'type' => 'varchar',
  867. 'length' => 50,
  868. 'not null' => FALSE,
  869. ),
  870. 'data' => array(
  871. 'description' => 'Some data needed for the task, might be optional depending on the type.',
  872. 'type' => 'text',
  873. 'size' => 'medium',
  874. 'serialize' => TRUE,
  875. 'not null' => FALSE,
  876. ),
  877. ),
  878. 'indexes' => array(
  879. 'server' => array('server_id'),
  880. ),
  881. 'primary key' => array('id'),
  882. );
  883. db_create_table('search_api_task', $table);
  884. // Collect old tasks.
  885. $tasks = array();
  886. foreach (variable_get('search_api_tasks', array()) as $server => $indexes) {
  887. foreach ($indexes as $index => $old_tasks) {
  888. if (in_array('clear all', $old_tasks)) {
  889. $tasks[] = array(
  890. 'server_id' => $server,
  891. 'type' => 'deleteItems',
  892. );
  893. }
  894. if (in_array('remove', $old_tasks)) {
  895. $tasks[] = array(
  896. 'server_id' => $server,
  897. 'type' => 'removeIndex',
  898. 'index_id' => $index,
  899. );
  900. }
  901. }
  902. }
  903. variable_del('search_api_tasks');
  904. $select = db_select('search_api_index', 'i')
  905. ->fields('i', array('machine_name', 'server'));
  906. $select->innerJoin('search_api_server', 's', 'i.server = s.machine_name AND s.enabled = 0');
  907. $index_ids = array();
  908. foreach ($select->execute() as $index) {
  909. $index_ids[] = $index->machine_name;
  910. $tasks[] = array(
  911. 'server_id' => $index->server,
  912. 'type' => 'removeIndex',
  913. 'index_id' => $index->machine_name,
  914. );
  915. }
  916. if ($index_ids) {
  917. db_update('search_api_index')
  918. ->fields(array(
  919. 'enabled' => 0,
  920. 'server' => NULL,
  921. ))
  922. ->condition('machine_name', $index_ids)
  923. ->execute();
  924. }
  925. if ($tasks) {
  926. $insert = db_insert('search_api_task')
  927. ->fields(array('server_id', 'type', 'index_id', 'data'));
  928. foreach ($tasks as $task) {
  929. $task += array(
  930. 'index_id' => NULL,
  931. 'data' => NULL,
  932. );
  933. $insert->values($task);
  934. }
  935. $insert->execute();
  936. }
  937. }
  938. /**
  939. * Checks the database for illegal {search_api_index}.server values.
  940. */
  941. function search_api_update_7117() {
  942. $servers = db_select('search_api_server', 's')
  943. ->fields('s', array('machine_name'))
  944. ->condition('enabled', 1);
  945. $indexes = db_select('search_api_index', 'i')
  946. ->fields('i', array('id'))
  947. ->condition('server', $servers, 'NOT IN')
  948. ->execute()
  949. ->fetchCol();
  950. if ($indexes) {
  951. db_delete('search_api_item')
  952. ->condition('index_id', $indexes)
  953. ->execute();
  954. db_update('search_api_index')
  955. ->fields(array(
  956. 'server' => NULL,
  957. 'enabled' => 0,
  958. ))
  959. ->condition('id', $indexes)
  960. ->execute();
  961. }
  962. }