service.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. <?php
  2. /**
  3. * @file
  4. * Contains SearchApiServiceInterface and SearchApiAbstractService.
  5. */
  6. /**
  7. * Interface defining the methods search services have to implement.
  8. *
  9. * Before a service object is used, the corresponding server's data will be read
  10. * from the database (see SearchApiAbstractService for a list of fields).
  11. *
  12. * Most methods in this interface (where any change in data occurs) can throw a
  13. * SearchApiException. The server entity class SearchApiServer catches these
  14. * exceptions and uses the server tasks system to assure that the action is
  15. * later retried.
  16. */
  17. interface SearchApiServiceInterface {
  18. /**
  19. * Constructs a service object.
  20. *
  21. * This will set the server configuration used with this service.
  22. *
  23. * @param SearchApiServer $server
  24. * The server object for this service.
  25. */
  26. public function __construct(SearchApiServer $server);
  27. /**
  28. * Form constructor for the server configuration form.
  29. *
  30. * Might be called with an incomplete server (no ID). In this case, the form
  31. * is displayed for the initial creation of the server.
  32. *
  33. * @param array $form
  34. * The server options part of the form.
  35. * @param array $form_state
  36. * The current form state.
  37. *
  38. * @return array
  39. * A form array for setting service-specific options.
  40. */
  41. public function configurationForm(array $form, array &$form_state);
  42. /**
  43. * Validation callback for the form returned by configurationForm().
  44. *
  45. * $form_state['server'] will contain the server that is created or edited.
  46. * Use form_error() to flag errors on form elements.
  47. *
  48. * @param array $form
  49. * The form returned by configurationForm().
  50. * @param array $values
  51. * The part of the $form_state['values'] array corresponding to this form.
  52. * @param array $form_state
  53. * The complete form state.
  54. */
  55. public function configurationFormValidate(array $form, array &$values, array &$form_state);
  56. /**
  57. * Submit callback for the form returned by configurationForm().
  58. *
  59. * This method should set the options of this service' server according to
  60. * $values.
  61. *
  62. * @param array $form
  63. * The form returned by configurationForm().
  64. * @param array $values
  65. * The part of the $form_state['values'] array corresponding to this form.
  66. * @param array $form_state
  67. * The complete form state.
  68. */
  69. public function configurationFormSubmit(array $form, array &$values, array &$form_state);
  70. /**
  71. * Determines whether this service class supports a given feature.
  72. *
  73. * Features are optional extensions to Search API functionality and usually
  74. * defined and used by third-party modules.
  75. *
  76. * There are currently three features defined directly in the Search API
  77. * project:
  78. * - "search_api_facets", by the search_api_facetapi module.
  79. * - "search_api_facets_operator_or", also by the search_api_facetapi module.
  80. * - "search_api_mlt", by the search_api_views module.
  81. * Other contrib modules might define additional features. These should always
  82. * be properly documented in the module by which they are defined.
  83. *
  84. * @param string $feature
  85. * The name of the optional feature.
  86. *
  87. * @return bool
  88. * TRUE if this service knows and supports the specified feature. FALSE
  89. * otherwise.
  90. */
  91. public function supportsFeature($feature);
  92. /**
  93. * Displays this server's settings.
  94. *
  95. * Output can be HTML or a render array, a <dl> listing all relevant settings
  96. * is preferred.
  97. */
  98. public function viewSettings();
  99. /**
  100. * Reacts to the server's creation.
  101. *
  102. * Called once, when the server is first created. Allows it to set up its
  103. * necessary infrastructure.
  104. */
  105. public function postCreate();
  106. /**
  107. * Notifies this server that its fields are about to be updated.
  108. *
  109. * The server's $original property can be used to inspect the old property
  110. * values.
  111. *
  112. * @return bool
  113. * TRUE, if the update requires reindexing of all content on the server.
  114. */
  115. public function postUpdate();
  116. /**
  117. * Notifies this server that it is about to be deleted from the database.
  118. *
  119. * This should execute any necessary cleanup operations.
  120. *
  121. * Note that you shouldn't call the server's save() method, or any
  122. * methods that might do that, from inside of this method as the server isn't
  123. * present in the database anymore at this point.
  124. */
  125. public function preDelete();
  126. /**
  127. * Adds a new index to this server.
  128. *
  129. * If the index was already added to the server, the object should treat this
  130. * as if removeIndex() and then addIndex() were called.
  131. *
  132. * @param SearchApiIndex $index
  133. * The index to add.
  134. *
  135. * @throws SearchApiException
  136. * If an error occurred while adding the index.
  137. */
  138. public function addIndex(SearchApiIndex $index);
  139. /**
  140. * Notifies the server that the field settings for the index have changed.
  141. *
  142. * If any user action is necessary as a result of this, the method should
  143. * use drupal_set_message() to notify the user.
  144. *
  145. * @param SearchApiIndex $index
  146. * The updated index.
  147. *
  148. * @return bool
  149. * TRUE, if this change affected the server in any way that forces it to
  150. * re-index the content. FALSE otherwise.
  151. *
  152. * @throws SearchApiException
  153. * If an error occurred while reacting to the change of fields.
  154. */
  155. public function fieldsUpdated(SearchApiIndex $index);
  156. /**
  157. * Removes an index from this server.
  158. *
  159. * This might mean that the index has been deleted, or reassigned to a
  160. * different server. If you need to distinguish between these cases, inspect
  161. * $index->server.
  162. *
  163. * If the index wasn't added to the server, the method call should be ignored.
  164. *
  165. * Implementations of this method should also check whether $index->read_only
  166. * is set, and don't delete any indexed data if it is.
  167. *
  168. * @param $index
  169. * Either an object representing the index to remove, or its machine name
  170. * (if the index was completely deleted).
  171. *
  172. * @throws SearchApiException
  173. * If an error occurred while removing the index.
  174. */
  175. public function removeIndex($index);
  176. /**
  177. * Indexes the specified items.
  178. *
  179. * @param SearchApiIndex $index
  180. * The search index for which items should be indexed.
  181. * @param array $items
  182. * An array of items to be indexed, keyed by their id. The values are
  183. * associative arrays of the fields to be stored, where each field is an
  184. * array with the following keys:
  185. * - type: One of the data types recognized by the Search API, or the
  186. * special type "tokens" for fulltext fields.
  187. * - original_type: The original type of the property, as defined by the
  188. * datasource controller for the index's item type.
  189. * - value: The value to index.
  190. *
  191. * The special field "search_api_language" contains the item's language and
  192. * should always be indexed.
  193. *
  194. * The value of fields with the "tokens" type is an array of tokens. Each
  195. * token is an array containing the following keys:
  196. * - value: The word that the token represents.
  197. * - score: A score for the importance of that word.
  198. *
  199. * @return array
  200. * An array of the ids of all items that were successfully indexed.
  201. *
  202. * @throws SearchApiException
  203. * If indexing was prevented by a fundamental configuration error.
  204. */
  205. public function indexItems(SearchApiIndex $index, array $items);
  206. /**
  207. * Deletes indexed items from this server.
  208. *
  209. * Might be either used to delete some items (given by their ids) from a
  210. * specified index, or all items from that index, or all items from all
  211. * indexes on this server.
  212. *
  213. * @param $ids
  214. * Either an array containing the ids of the items that should be deleted,
  215. * or 'all' if all items should be deleted. Other formats might be
  216. * recognized by implementing classes, but these are not standardized.
  217. * @param SearchApiIndex $index
  218. * The index from which items should be deleted, or NULL if all indexes on
  219. * this server should be cleared (then, $ids has to be 'all').
  220. *
  221. * @throws SearchApiException
  222. * If an error occurred while trying to delete the items.
  223. */
  224. public function deleteItems($ids = 'all', SearchApiIndex $index = NULL);
  225. /**
  226. * Creates a query object for searching on an index lying on this server.
  227. *
  228. * @param SearchApiIndex $index
  229. * The index to search on.
  230. * @param $options
  231. * Associative array of options configuring this query. See
  232. * SearchApiQueryInterface::__construct().
  233. *
  234. * @return SearchApiQueryInterface
  235. * An object for searching the given index.
  236. *
  237. * @throws SearchApiException
  238. * If the server is currently disabled.
  239. */
  240. public function query(SearchApiIndex $index, $options = array());
  241. /**
  242. * Executes a search on the server represented by this object.
  243. *
  244. * @param $query
  245. * The SearchApiQueryInterface object to execute.
  246. *
  247. * @return array
  248. * An associative array containing the search results, as required by
  249. * SearchApiQueryInterface::execute().
  250. *
  251. * @throws SearchApiException
  252. * If an error prevented the search from completing.
  253. */
  254. public function search(SearchApiQueryInterface $query);
  255. }
  256. /**
  257. * Abstract class with generic implementation of most service methods.
  258. *
  259. * For creating your own service class extending this class, you only need to
  260. * implement indexItems(), deleteItems() and search() from the
  261. * SearchApiServiceInterface interface.
  262. */
  263. abstract class SearchApiAbstractService implements SearchApiServiceInterface {
  264. /**
  265. * @var SearchApiServer
  266. */
  267. protected $server;
  268. /**
  269. * Direct reference to the server's $options property.
  270. *
  271. * @var array
  272. */
  273. protected $options = array();
  274. /**
  275. * Implements SearchApiServiceInterface::__construct().
  276. *
  277. * The default implementation sets $this->server and $this->options.
  278. */
  279. public function __construct(SearchApiServer $server) {
  280. $this->server = $server;
  281. $this->options = &$server->options;
  282. }
  283. /**
  284. * Implements SearchApiServiceInterface::__construct().
  285. *
  286. * Returns an empty form by default.
  287. */
  288. public function configurationForm(array $form, array &$form_state) {
  289. return array();
  290. }
  291. /**
  292. * Implements SearchApiServiceInterface::__construct().
  293. *
  294. * Does nothing by default.
  295. */
  296. public function configurationFormValidate(array $form, array &$values, array &$form_state) {
  297. return;
  298. }
  299. /**
  300. * Implements SearchApiServiceInterface::__construct().
  301. *
  302. * The default implementation just ensures that additional elements in
  303. * $options, not present in the form, don't get lost at the update.
  304. */
  305. public function configurationFormSubmit(array $form, array &$values, array &$form_state) {
  306. if (!empty($this->options)) {
  307. $values += $this->options;
  308. }
  309. $this->options = $values;
  310. }
  311. /**
  312. * Implements SearchApiServiceInterface::__construct().
  313. *
  314. * The default implementation always returns FALSE.
  315. */
  316. public function supportsFeature($feature) {
  317. return FALSE;
  318. }
  319. /**
  320. * Implements SearchApiServiceInterface::__construct().
  321. *
  322. * The default implementation does a crude output as a definition list, with
  323. * option names taken from the configuration form.
  324. */
  325. public function viewSettings() {
  326. $output = '';
  327. $form = $form_state = array();
  328. $option_form = $this->configurationForm($form, $form_state);
  329. $option_names = array();
  330. foreach ($option_form as $key => $element) {
  331. if (isset($element['#title']) && isset($this->options[$key])) {
  332. $option_names[$key] = $element['#title'];
  333. }
  334. }
  335. foreach ($option_names as $key => $name) {
  336. $value = $this->options[$key];
  337. $output .= '<dt>' . check_plain($name) . '</dt>' . "\n";
  338. $output .= '<dd>' . nl2br(check_plain(print_r($value, TRUE))) . '</dd>' . "\n";
  339. }
  340. return $output ? "<dl>\n$output</dl>" : '';
  341. }
  342. /**
  343. * Returns additional, service-specific information about this server.
  344. *
  345. * If a service class implements this method and supports the
  346. * "search_api_service_extra" option, this method will be used to add extra
  347. * information to the server's "View" tab.
  348. *
  349. * In the default theme implementation this data will be output in a table
  350. * with two columns along with other, generic information about the server.
  351. *
  352. * @return array
  353. * An array of additional server information, with each piece of information
  354. * being an associative array with the following keys:
  355. * - label: The human-readable label for this data.
  356. * - info: The information, as HTML.
  357. * - status: (optional) The status associated with this information. One of
  358. * "info", "ok", "warning" or "error". Defaults to "info".
  359. *
  360. * @see supportsFeature()
  361. */
  362. public function getExtraInformation() {
  363. return array();
  364. }
  365. /**
  366. * Implements SearchApiServiceInterface::__construct().
  367. *
  368. * Does nothing, by default.
  369. */
  370. public function postCreate() {
  371. return;
  372. }
  373. /**
  374. * Implements SearchApiServiceInterface::__construct().
  375. *
  376. * The default implementation always returns FALSE.
  377. */
  378. public function postUpdate() {
  379. return FALSE;
  380. }
  381. /**
  382. * Implements SearchApiServiceInterface::__construct().
  383. *
  384. * By default, deletes all indexes from this server.
  385. */
  386. public function preDelete() {
  387. $indexes = search_api_index_load_multiple(FALSE, array('server' => $this->server->machine_name));
  388. foreach ($indexes as $index) {
  389. // removeIndex() might throw exceptions, but this method mustn't.
  390. try {
  391. $this->removeIndex($index);
  392. }
  393. catch (SearchApiException $e) {
  394. $variables['%index'] = $index->name;
  395. $variables['%server'] = $this->server->name;
  396. watchdog_exception('search_api', $e, '%type while trying to remove index %index from deleted server %server: !message in %function (line %line of %file).', $variables);
  397. }
  398. }
  399. }
  400. /**
  401. * Implements SearchApiServiceInterface::__construct().
  402. *
  403. * Does nothing, by default.
  404. */
  405. public function addIndex(SearchApiIndex $index) {
  406. return;
  407. }
  408. /**
  409. * Implements SearchApiServiceInterface::__construct().
  410. *
  411. * The default implementation always returns FALSE.
  412. */
  413. public function fieldsUpdated(SearchApiIndex $index) {
  414. return FALSE;
  415. }
  416. /**
  417. * Implements SearchApiServiceInterface::__construct().
  418. *
  419. * By default, removes all items from that index.
  420. */
  421. public function removeIndex($index) {
  422. if (is_object($index) && empty($index->read_only)) {
  423. $this->deleteItems('all', $index);
  424. }
  425. }
  426. /**
  427. * Implements SearchApiServiceInterface::__construct().
  428. *
  429. * The default implementation returns a SearchApiQuery object.
  430. */
  431. public function query(SearchApiIndex $index, $options = array()) {
  432. return new SearchApiQuery($index, $options);
  433. }
  434. }