datasource.inc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. <?php
  2. /**
  3. * @file
  4. * Contains the SearchApiDataSourceControllerInterface as well as a default base class.
  5. */
  6. /**
  7. * Interface for all data source controllers for Search API indexes.
  8. *
  9. * Data source controllers encapsulate all operations specific to an item type.
  10. * They are used for loading items, extracting item data, keeping track of the
  11. * item status, etc.
  12. *
  13. * Modules providing implementations of this interface that use a different way
  14. * (either different table or different method altogether) of keeping track of
  15. * indexed/dirty items than SearchApiAbstractDataSourceController should be
  16. * aware that indexes' numerical IDs can change due to feature reverts. It is
  17. * therefore recommended to use search_api_index_update_datasource(), or similar
  18. * code, in a hook_search_api_index_update() implementation.
  19. */
  20. interface SearchApiDataSourceControllerInterface {
  21. /**
  22. * Constructs an SearchApiDataSourceControllerInterface object.
  23. *
  24. * @param string $type
  25. * The item type for which this controller is created.
  26. */
  27. public function __construct($type);
  28. /**
  29. * Returns information on the ID field for this controller's type.
  30. *
  31. * @return array
  32. * An associative array containing the following keys:
  33. * - key: The property key for the ID field, as used in the item wrapper.
  34. * - type: The type of the ID field. Has to be one of the types from
  35. * search_api_field_types(). List types ("list<*>") are not allowed.
  36. *
  37. * @throws SearchApiDataSourceException
  38. * If any error state was encountered.
  39. */
  40. public function getIdFieldInfo();
  41. /**
  42. * Loads items of the type of this data source controller.
  43. *
  44. * @param array $ids
  45. * The IDs of the items to load.
  46. *
  47. * @return array
  48. * The loaded items, keyed by ID.
  49. *
  50. * @throws SearchApiDataSourceException
  51. * If any error state was encountered.
  52. */
  53. public function loadItems(array $ids);
  54. /**
  55. * Creates a metadata wrapper for this datasource controller's type.
  56. *
  57. * @param mixed $item
  58. * Unless NULL, an item of the item type for this controller to be wrapped.
  59. * @param array $info
  60. * Optionally, additional information that should be used for creating the
  61. * wrapper. Uses the same format as entity_metadata_wrapper().
  62. *
  63. * @return EntityMetadataWrapper
  64. * A wrapper for the item type of this data source controller, according to
  65. * the info array, and optionally loaded with the given data.
  66. *
  67. * @throws SearchApiDataSourceException
  68. * If any error state was encountered.
  69. *
  70. * @see entity_metadata_wrapper()
  71. */
  72. public function getMetadataWrapper($item = NULL, array $info = array());
  73. /**
  74. * Retrieves the unique ID of an item.
  75. *
  76. * @param mixed $item
  77. * An item of this controller's type.
  78. *
  79. * @return mixed
  80. * Either the unique ID of the item, or NULL if none is available.
  81. *
  82. * @throws SearchApiDataSourceException
  83. * If any error state was encountered.
  84. */
  85. public function getItemId($item);
  86. /**
  87. * Retrieves a human-readable label for an item.
  88. *
  89. * @param mixed $item
  90. * An item of this controller's type.
  91. *
  92. * @return string|null
  93. * Either a human-readable label for the item, or NULL if none is available.
  94. *
  95. * @throws SearchApiDataSourceException
  96. * If any error state was encountered.
  97. */
  98. public function getItemLabel($item);
  99. /**
  100. * Retrieves a URL at which the item can be viewed on the web.
  101. *
  102. * @param mixed $item
  103. * An item of this controller's type.
  104. *
  105. * @return array|null
  106. * Either an array containing the 'path' and 'options' keys used to build
  107. * the URL of the item, and matching the signature of url(), or NULL if the
  108. * item has no URL of its own.
  109. *
  110. * @throws SearchApiDataSourceException
  111. * If any error state was encountered.
  112. */
  113. public function getItemUrl($item);
  114. /**
  115. * Initializes tracking of the index status of items for the given indexes.
  116. *
  117. * All currently known items of this data source's type should be inserted
  118. * into the tracking table for the given indexes, with status "changed". If
  119. * items were already present, these should also be set to "changed" and not
  120. * be inserted again.
  121. *
  122. * @param SearchApiIndex[] $indexes
  123. * The SearchApiIndex objects for which item tracking should be initialized.
  124. *
  125. * @throws SearchApiDataSourceException
  126. * If any error state was encountered.
  127. */
  128. public function startTracking(array $indexes);
  129. /**
  130. * Stops tracking of the index status of items for the given indexes.
  131. *
  132. * The tracking tables of the given indexes should be completely cleared.
  133. *
  134. * @param SearchApiIndex[] $indexes
  135. * The SearchApiIndex objects for which item tracking should be stopped.
  136. *
  137. * @throws SearchApiDataSourceException
  138. * If any error state was encountered.
  139. */
  140. public function stopTracking(array $indexes);
  141. /**
  142. * Starts tracking the index status for the given items on the given indexes.
  143. *
  144. * @param array $item_ids
  145. * The IDs of new items to track.
  146. * @param SearchApiIndex[] $indexes
  147. * The indexes for which items should be tracked.
  148. *
  149. * @return SearchApiIndex[]|null
  150. * All indexes for which any items were added; or NULL if items were added
  151. * for all of them.
  152. *
  153. * @throws SearchApiDataSourceException
  154. * If any error state was encountered.
  155. */
  156. public function trackItemInsert(array $item_ids, array $indexes);
  157. /**
  158. * Sets the tracking status of the given items to "changed"/"dirty".
  159. *
  160. * Unless $dequeue is set to TRUE, this operation is ignored for items whose
  161. * status is not "indexed".
  162. *
  163. * @param array|false $item_ids
  164. * Either an array with the IDs of the changed items. Or FALSE to mark all
  165. * items as changed for the given indexes.
  166. * @param SearchApiIndex[] $indexes
  167. * The indexes for which the change should be tracked.
  168. * @param bool $dequeue
  169. * (deprecated) If set to TRUE, also change the status of queued items.
  170. * The concept of queued items will be removed in the Drupal 8 version of
  171. * this module.
  172. *
  173. * @return SearchApiIndex[]|null
  174. * All indexes for which any items were updated; or NULL if items were
  175. * updated for all of them.
  176. *
  177. * @throws SearchApiDataSourceException
  178. * If any error state was encountered.
  179. */
  180. public function trackItemChange($item_ids, array $indexes, $dequeue = FALSE);
  181. /**
  182. * Sets the tracking status of the given items to "queued".
  183. *
  184. * Queued items are not marked as "dirty" even when they are changed, and they
  185. * are not returned by the getChangedItems() method.
  186. *
  187. * @param array|false $item_ids
  188. * Either an array with the IDs of the queued items. Or FALSE to mark all
  189. * items as queued for the given indexes.
  190. * @param SearchApiIndex $index
  191. * The index for which the items were queued.
  192. *
  193. * @throws SearchApiDataSourceException
  194. * If any error state was encountered.
  195. *
  196. * @deprecated
  197. * As of Search API 1.10, the cron queue is not used for indexing anymore,
  198. * therefore this method has become useless. It will be removed in the
  199. * Drupal 8 version of this module.
  200. */
  201. public function trackItemQueued($item_ids, SearchApiIndex $index);
  202. /**
  203. * Sets the tracking status of the given items to "indexed".
  204. *
  205. * @param array $item_ids
  206. * The IDs of the indexed items.
  207. * @param SearchApiIndex $index
  208. * The index on which the items were indexed.
  209. *
  210. * @throws SearchApiDataSourceException
  211. * If any error state was encountered.
  212. */
  213. public function trackItemIndexed(array $item_ids, SearchApiIndex $index);
  214. /**
  215. * Stops tracking the index status for the given items on the given indexes.
  216. *
  217. * @param array $item_ids
  218. * The IDs of the removed items.
  219. * @param SearchApiIndex[] $indexes
  220. * The indexes for which the deletions should be tracked.
  221. *
  222. * @return SearchApiIndex[]|null
  223. * All indexes for which any items were deleted; or NULL if items were
  224. * deleted for all of them.
  225. *
  226. * @throws SearchApiDataSourceException
  227. * If any error state was encountered.
  228. */
  229. public function trackItemDelete(array $item_ids, array $indexes);
  230. /**
  231. * Retrieves a list of items that need to be indexed.
  232. *
  233. * If possible, completely unindexed items should be returned before items
  234. * that were indexed but later changed. Also, items that were changed longer
  235. * ago should be favored.
  236. *
  237. * @param SearchApiIndex $index
  238. * The index for which changed items should be returned.
  239. * @param int $limit
  240. * The maximum number of items to return. Negative values mean "unlimited".
  241. *
  242. * @return array
  243. * The IDs of items that need to be indexed for the given index.
  244. *
  245. * @throws SearchApiDataSourceException
  246. * If any error state was encountered.
  247. */
  248. public function getChangedItems(SearchApiIndex $index, $limit = -1);
  249. /**
  250. * Retrieves information on how many items have been indexed for a certain index.
  251. *
  252. * @param SearchApiIndex $index
  253. * The index whose index status should be returned.
  254. *
  255. * @return array
  256. * An associative array containing two keys (in this order):
  257. * - indexed: The number of items already indexed in their latest version.
  258. * - total: The total number of items that have to be indexed for this
  259. * index.
  260. *
  261. * @throws SearchApiDataSourceException
  262. * If any error state was encountered.
  263. */
  264. public function getIndexStatus(SearchApiIndex $index);
  265. /**
  266. * Retrieves the entity type of items from this datasource.
  267. *
  268. * @return string|null
  269. * An entity type string if the items provided by this datasource are
  270. * entities; NULL otherwise.
  271. *
  272. * @throws SearchApiDataSourceException
  273. * If any error state was encountered.
  274. */
  275. public function getEntityType();
  276. /**
  277. * Form constructor for configuring the datasource for a given index.
  278. *
  279. * @param array $form
  280. * The form returned by configurationForm().
  281. * @param array $form_state
  282. * The form state. $form_state['index'] will contain the edited index. If
  283. * this key is empty, then a new index is being created. In case of an edit,
  284. * $form_state['index']->options['datasource'] contains the previous
  285. * settings for the datasource.
  286. *
  287. * @return array|false
  288. * A form array for configuring this callback, or FALSE if no configuration
  289. * is possible.
  290. */
  291. public function configurationForm(array $form, array &$form_state);
  292. /**
  293. * Validation callback for the form returned by configurationForm().
  294. *
  295. * This method will only be called if that form was non-empty.
  296. *
  297. * @param array $form
  298. * The form returned by configurationForm().
  299. * @param array $values
  300. * The part of the $form_state['values'] array corresponding to this form.
  301. * @param array $form_state
  302. * The complete form state.
  303. */
  304. public function configurationFormValidate(array $form, array &$values, array &$form_state);
  305. /**
  306. * Submit callback for the form returned by configurationForm().
  307. *
  308. * This method will only be called if that form was non-empty.
  309. *
  310. * Any necessary changes to the submitted values should be made, afterwards
  311. * they will automatically be stored as the index's "datasource" options. The
  312. * method can also be used by the datasource controller to react to the
  313. * possible change in its settings.
  314. *
  315. * @param array $form
  316. * The form returned by configurationForm().
  317. * @param array $values
  318. * The part of the $form_state['values'] array corresponding to this form.
  319. * @param array $form_state
  320. * The complete form state.
  321. */
  322. public function configurationFormSubmit(array $form, array &$values, array &$form_state);
  323. /**
  324. * Returns a summary of an index's current datasource configuration.
  325. *
  326. * @param SearchApiIndex $index
  327. * The index whose datasource configuration should be summarized.
  328. *
  329. * @return string|null
  330. * A translated string describing the index's current datasource
  331. * configuration. Or NULL, if there is no configuration (or no description
  332. * is available).
  333. */
  334. public function getConfigurationSummary(SearchApiIndex $index);
  335. }
  336. /**
  337. * Provides a default base class for datasource controllers.
  338. *
  339. * Contains default implementations for a number of methods which will be
  340. * similar for most data sources. Concrete data sources can decide to extend
  341. * this base class to save time, but can also implement the interface directly.
  342. *
  343. * A subclass will still have to provide implementations for the following
  344. * methods:
  345. * - getIdFieldInfo()
  346. * - loadItems()
  347. * - getMetadataWrapper() or getPropertyInfo()
  348. * - startTracking() or getAllItemIds()
  349. *
  350. * The table used by default for tracking the index status of items is
  351. * {search_api_item}. This can easily be changed, for example when an item type
  352. * has non-integer IDs, by changing the $table property.
  353. */
  354. abstract class SearchApiAbstractDataSourceController implements SearchApiDataSourceControllerInterface {
  355. /**
  356. * The item type for this controller instance.
  357. */
  358. protected $type;
  359. /**
  360. * The entity type for this controller instance.
  361. *
  362. * @var string|null
  363. *
  364. * @see getEntityType()
  365. */
  366. protected $entityType = NULL;
  367. /**
  368. * The info array for the item type, as specified via
  369. * hook_search_api_item_type_info().
  370. *
  371. * @var array
  372. */
  373. protected $info;
  374. /**
  375. * The table used for tracking items. Set to NULL on subclasses to disable
  376. * the default tracking for an item type, or change the property to use a
  377. * different table for tracking.
  378. *
  379. * @var string
  380. */
  381. protected $table = 'search_api_item';
  382. /**
  383. * When using the default tracking mechanism: the name of the column on
  384. * $this->table containing the item ID.
  385. *
  386. * @var string
  387. */
  388. protected $itemIdColumn = 'item_id';
  389. /**
  390. * When using the default tracking mechanism: the name of the column on
  391. * $this->table containing the index ID.
  392. *
  393. * @var string
  394. */
  395. protected $indexIdColumn = 'index_id';
  396. /**
  397. * When using the default tracking mechanism: the name of the column on
  398. * $this->table containing the indexing status.
  399. *
  400. * @var string
  401. */
  402. protected $changedColumn = 'changed';
  403. /**
  404. * {@inheritdoc}
  405. */
  406. public function __construct($type) {
  407. $this->type = $type;
  408. $this->info = search_api_get_item_type_info($type);
  409. if (!empty($this->info['entity_type'])) {
  410. $this->entityType = $this->info['entity_type'];
  411. }
  412. }
  413. /**
  414. * {@inheritdoc}
  415. */
  416. public function getEntityType() {
  417. return $this->entityType;
  418. }
  419. /**
  420. * {@inheritdoc}
  421. */
  422. public function getMetadataWrapper($item = NULL, array $info = array()) {
  423. $info += $this->getPropertyInfo();
  424. return entity_metadata_wrapper($this->entityType ? $this->entityType : $this->type, $item, $info);
  425. }
  426. /**
  427. * Retrieves the property info for this item type.
  428. *
  429. * This is a helper method for getMetadataWrapper() that can be used by
  430. * subclasses to specify the property information to use when creating a
  431. * metadata wrapper.
  432. *
  433. * The data structure uses largely the format specified in
  434. * hook_entity_property_info(). However, the first level of keys (containing
  435. * the entity types) is omitted, and the "properties" key is called
  436. * "property info" instead. So, an example return value would look like this:
  437. *
  438. * @code
  439. * return array(
  440. * 'property info' => array(
  441. * 'foo' => array(
  442. * 'label' => t('Foo'),
  443. * 'type' => 'text',
  444. * ),
  445. * 'bar' => array(
  446. * 'label' => t('Bar'),
  447. * 'type' => 'list<integer>',
  448. * ),
  449. * ),
  450. * );
  451. * @endcode
  452. *
  453. * SearchApiExternalDataSourceController::getPropertyInfo() contains a working
  454. * example of this method.
  455. *
  456. * If the item type is an entity type, no additional property information is
  457. * required, the method will thus just return an empty array. You can still
  458. * use this to append additional properties to the entities, or the like,
  459. * though.
  460. *
  461. * @return array
  462. * Property information as specified by entity_metadata_wrapper().
  463. *
  464. * @throws SearchApiDataSourceException
  465. * If any error state was encountered.
  466. *
  467. * @see getMetadataWrapper()
  468. * @see hook_entity_property_info()
  469. */
  470. protected function getPropertyInfo() {
  471. // If this is an entity type, no additional property info is needed.
  472. if ($this->entityType) {
  473. return array();
  474. }
  475. throw new SearchApiDataSourceException(t('No known property information for type @type.', array('@type' => $this->type)));
  476. }
  477. /**
  478. * {@inheritdoc}
  479. */
  480. public function getItemId($item) {
  481. $id_info = $this->getIdFieldInfo();
  482. $field = $id_info['key'];
  483. $wrapper = $this->getMetadataWrapper($item);
  484. if (!isset($wrapper->$field)) {
  485. return NULL;
  486. }
  487. $id = $wrapper->$field->value();
  488. return $id ? $id : NULL;
  489. }
  490. /**
  491. * {@inheritdoc}
  492. */
  493. public function getItemLabel($item) {
  494. $label = $this->getMetadataWrapper($item)->label();
  495. return $label ? $label : NULL;
  496. }
  497. /**
  498. * {@inheritdoc}
  499. */
  500. public function getItemUrl($item) {
  501. return NULL;
  502. }
  503. /**
  504. * {@inheritdoc}
  505. */
  506. public function startTracking(array $indexes) {
  507. if (!$this->table) {
  508. return;
  509. }
  510. // We first clear the tracking table for all indexes, so we can just insert
  511. // all items again without any key conflicts.
  512. $this->stopTracking($indexes);
  513. // Insert all items as new.
  514. $this->trackItemInsert($this->getAllItemIds(), $indexes);
  515. }
  516. /**
  517. * Returns the IDs of all items that are known for this controller's type.
  518. *
  519. * Helper method that can be used by subclasses instead of implementing
  520. * startTracking().
  521. *
  522. * @return array
  523. * An array containing all item IDs for this type.
  524. *
  525. * @throws SearchApiDataSourceException
  526. * If any error state was encountered.
  527. */
  528. protected function getAllItemIds() {
  529. throw new SearchApiDataSourceException(t('Items not known for type @type.', array('@type' => $this->type)));
  530. }
  531. /**
  532. * {@inheritdoc}
  533. */
  534. public function stopTracking(array $indexes) {
  535. if (!$this->table) {
  536. return;
  537. }
  538. // We could also use a single query with "IN" operator, but this method
  539. // will mostly be called with only one index.
  540. foreach ($indexes as $index) {
  541. $this->checkIndex($index);
  542. db_delete($this->table)
  543. ->condition($this->indexIdColumn, $index->id)
  544. ->execute();
  545. }
  546. }
  547. /**
  548. * {@inheritdoc}
  549. */
  550. public function trackItemInsert(array $item_ids, array $indexes) {
  551. if (!$this->table || $item_ids === array()) {
  552. return;
  553. }
  554. foreach ($indexes as $index) {
  555. $this->checkIndex($index);
  556. }
  557. // Since large amounts of items can overstrain the database, only add items
  558. // in chunks.
  559. foreach (array_chunk($item_ids, 1000) as $chunk) {
  560. $insert = db_insert($this->table)
  561. ->fields(array($this->itemIdColumn, $this->indexIdColumn, $this->changedColumn));
  562. foreach ($chunk as $item_id) {
  563. foreach ($indexes as $index) {
  564. $insert->values(array(
  565. $this->itemIdColumn => $item_id,
  566. $this->indexIdColumn => $index->id,
  567. $this->changedColumn => 1,
  568. ));
  569. }
  570. }
  571. $insert->execute();
  572. }
  573. }
  574. /**
  575. * {@inheritdoc}
  576. */
  577. public function trackItemChange($item_ids, array $indexes, $dequeue = FALSE) {
  578. if (!$this->table || $item_ids === array()) {
  579. return NULL;
  580. }
  581. $indexes_by_id = array();
  582. foreach ($indexes as $index) {
  583. $this->checkIndex($index);
  584. $update = db_update($this->table)
  585. ->fields(array(
  586. $this->changedColumn => REQUEST_TIME,
  587. ))
  588. ->condition($this->indexIdColumn, $index->id)
  589. ->condition($this->changedColumn, 0, $dequeue ? '<=' : '=');
  590. if ($item_ids !== FALSE) {
  591. $update->condition($this->itemIdColumn, $item_ids, 'IN');
  592. }
  593. $update->execute();
  594. $indexes_by_id[$index->id] = $index;
  595. }
  596. // Determine and return the indexes with any changed items. If $item_ids is
  597. // FALSE, all items are marked as changed and, thus, all indexes will be
  598. // affected (unless they don't have any items, but no real point in treating
  599. // that special case).
  600. if ($item_ids !== FALSE) {
  601. $indexes_with_items = db_select($this->table, 't')
  602. ->fields('t', array($this->indexIdColumn))
  603. ->distinct()
  604. ->condition($this->indexIdColumn, array_keys($indexes_by_id), 'IN')
  605. ->condition($this->itemIdColumn, $item_ids, 'IN')
  606. ->execute()
  607. ->fetchCol();
  608. return array_intersect_key($indexes_by_id, array_flip($indexes_with_items));
  609. }
  610. return NULL;
  611. }
  612. /**
  613. * {@inheritdoc}
  614. */
  615. public function trackItemQueued($item_ids, SearchApiIndex $index) {
  616. $this->checkIndex($index);
  617. if (!$this->table || $item_ids === array()) {
  618. return;
  619. }
  620. $update = db_update($this->table)
  621. ->fields(array(
  622. $this->changedColumn => -1,
  623. ))
  624. ->condition($this->indexIdColumn, $index->id);
  625. if ($item_ids !== FALSE) {
  626. $update->condition($this->itemIdColumn, $item_ids, 'IN');
  627. }
  628. $update->execute();
  629. }
  630. /**
  631. * {@inheritdoc}
  632. */
  633. public function trackItemIndexed(array $item_ids, SearchApiIndex $index) {
  634. if (!$this->table || $item_ids === array()) {
  635. return;
  636. }
  637. $this->checkIndex($index);
  638. db_update($this->table)
  639. ->fields(array(
  640. $this->changedColumn => 0,
  641. ))
  642. ->condition($this->itemIdColumn, $item_ids, 'IN')
  643. ->condition($this->indexIdColumn, $index->id)
  644. ->execute();
  645. }
  646. /**
  647. * {@inheritdoc}
  648. */
  649. public function trackItemDelete(array $item_ids, array $indexes) {
  650. if (!$this->table || $item_ids === array()) {
  651. return NULL;
  652. }
  653. $ret = array();
  654. foreach ($indexes as $index) {
  655. $this->checkIndex($index);
  656. $delete = db_delete($this->table)
  657. ->condition($this->indexIdColumn, $index->id)
  658. ->condition($this->itemIdColumn, $item_ids, 'IN');
  659. if ($delete->execute()) {
  660. $ret[] = $index;
  661. }
  662. }
  663. return $ret;
  664. }
  665. /**
  666. * {@inheritdoc}
  667. */
  668. public function getChangedItems(SearchApiIndex $index, $limit = -1) {
  669. if ($limit == 0) {
  670. return array();
  671. }
  672. $this->checkIndex($index);
  673. $select = db_select($this->table, 't');
  674. $select->addField('t', $this->itemIdColumn);
  675. $select->condition($this->indexIdColumn, $index->id);
  676. $select->condition($this->changedColumn, 0, '>');
  677. $select->orderBy($this->changedColumn, 'ASC');
  678. if ($limit > 0) {
  679. $select->range(0, $limit);
  680. }
  681. return $select->execute()->fetchCol();
  682. }
  683. /**
  684. * {@inheritdoc}
  685. */
  686. public function getIndexStatus(SearchApiIndex $index) {
  687. if (!$this->table) {
  688. return array('indexed' => 0, 'total' => 0);
  689. }
  690. $this->checkIndex($index);
  691. $indexed = db_select($this->table, 'i')
  692. ->condition($this->indexIdColumn, $index->id)
  693. ->condition($this->changedColumn, 0)
  694. ->countQuery()
  695. ->execute()
  696. ->fetchField();
  697. $total = db_select($this->table, 'i')
  698. ->condition($this->indexIdColumn, $index->id)
  699. ->countQuery()
  700. ->execute()
  701. ->fetchField();
  702. return array('indexed' => $indexed, 'total' => $total);
  703. }
  704. /**
  705. * {@inheritdoc}
  706. */
  707. public function configurationForm(array $form, array &$form_state) {
  708. return FALSE;
  709. }
  710. /**
  711. * {@inheritdoc}
  712. */
  713. public function configurationFormValidate(array $form, array &$values, array &$form_state) {
  714. }
  715. /**
  716. * {@inheritdoc}
  717. */
  718. public function configurationFormSubmit(array $form, array &$values, array &$form_state) {
  719. }
  720. /**
  721. * {@inheritdoc}
  722. */
  723. public function getConfigurationSummary(SearchApiIndex $index) {
  724. return NULL;
  725. }
  726. /**
  727. * Checks whether the given index is valid for this datasource controller.
  728. *
  729. * Helper method used by various methods in this class. By default only checks
  730. * whether the types match.
  731. *
  732. * @param SearchApiIndex $index
  733. * The index to check.
  734. *
  735. * @throws SearchApiDataSourceException
  736. * If the index doesn't fit to this datasource controller.
  737. */
  738. protected function checkIndex(SearchApiIndex $index) {
  739. if ($index->item_type != $this->type) {
  740. $index_type = search_api_get_item_type_info($index->item_type);
  741. $index_type = empty($index_type['name']) ? $index->item_type : $index_type['name'];
  742. $msg = t(
  743. 'Invalid index @index of type @index_type passed to data source controller for type @this_type.',
  744. array('@index' => $index->name, '@index_type' => $index_type, '@this_type' => $this->info['name'])
  745. );
  746. throw new SearchApiDataSourceException($msg);
  747. }
  748. }
  749. }