View source
<?php
namespace Drupal\search_api\Plugin\search_api\tracker;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\search_api\LoggerTrait;
use Drupal\search_api\Plugin\PluginFormTrait;
use Drupal\search_api\Tracker\TrackerPluginBase;
use Drupal\search_api\Utility\Utility;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Basic extends TrackerPluginBase implements PluginFormInterface {
use LoggerTrait;
use PluginFormTrait;
const STATUS_INDEXED = 0;
const STATUS_NOT_INDEXED = 1;
protected $connection;
protected $timeService;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$tracker = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$tracker
->setDatabaseConnection($container
->get('database'));
$tracker
->setTimeService($container
->get('datetime.time'));
return $tracker;
}
public function getDatabaseConnection() {
return $this->connection ?: \Drupal::database();
}
public function setDatabaseConnection(Connection $connection) {
$this->connection = $connection;
return $this;
}
public function getTimeService() {
return $this->timeService ?: \Drupal::time();
}
public function setTimeService(TimeInterface $time_service) {
$this->timeService = $time_service;
return $this;
}
public function defaultConfiguration() {
return [
'indexing_order' => 'fifo',
];
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form['indexing_order'] = [
'#type' => 'radios',
'#title' => $this
->t('Indexing order'),
'#description' => $this
->t('The order in which items will be indexed.'),
'#options' => [
'fifo' => $this
->t('Index items in the same order in which they were saved'),
'lifo' => $this
->t('Index the most recent items first'),
],
'#default_value' => $this->configuration['indexing_order'],
];
return $form;
}
protected function createSelectStatement() {
$select = $this
->getDatabaseConnection()
->select('search_api_item', 'sai');
$select
->condition('index_id', $this
->getIndex()
->id());
return $select;
}
protected function createInsertStatement() {
return $this
->getDatabaseConnection()
->insert('search_api_item')
->fields([
'index_id',
'datasource',
'item_id',
'changed',
'status',
]);
}
protected function createUpdateStatement() {
return $this
->getDatabaseConnection()
->update('search_api_item')
->condition('index_id', $this
->getIndex()
->id());
}
protected function createDeleteStatement() {
return $this
->getDatabaseConnection()
->delete('search_api_item')
->condition('index_id', $this
->getIndex()
->id());
}
protected function createRemainingItemsStatement($datasource_id = NULL) {
$select = $this
->createSelectStatement();
$select
->fields('sai', [
'item_id',
]);
if ($datasource_id) {
$select
->condition('datasource', $datasource_id);
}
$select
->condition('sai.status', $this::STATUS_NOT_INDEXED, '=');
$order = $this->configuration['indexing_order'] === 'lifo' ? 'DESC' : 'ASC';
$select
->orderBy('sai.changed', $order);
$select
->orderBy('sai.item_id', $order);
return $select;
}
public function trackItemsInserted(array $ids) {
try {
$index_id = $this
->getIndex()
->id();
foreach (array_chunk($ids, 1000) as $ids_chunk) {
$select = $this
->createSelectStatement()
->fields('sai', [
'item_id',
]);
$select
->condition('item_id', $ids_chunk, 'IN');
$existing = $select
->execute()
->fetchCol();
$existing = array_flip($existing);
$insert = $this
->createInsertStatement();
foreach ($ids_chunk as $item_id) {
if (isset($existing[$item_id])) {
continue;
}
list($datasource_id) = Utility::splitCombinedId($item_id);
$insert
->values([
'index_id' => $index_id,
'datasource' => $datasource_id,
'item_id' => $item_id,
'changed' => $this
->getTimeService()
->getRequestTime(),
'status' => $this::STATUS_NOT_INDEXED,
]);
}
if ($insert
->count()) {
$insert
->execute();
}
}
} catch (\Exception $e) {
$this
->logException($e);
}
}
public function trackItemsUpdated(array $ids = NULL) {
try {
$ids_chunks = $ids !== NULL ? array_chunk($ids, 1000) : [
NULL,
];
foreach ($ids_chunks as $ids_chunk) {
$update = $this
->createUpdateStatement();
$update
->fields([
'changed' => $this
->getTimeService()
->getRequestTime(),
'status' => $this::STATUS_NOT_INDEXED,
]);
if ($ids_chunk) {
$update
->condition('item_id', $ids_chunk, 'IN');
}
if ($this->configuration['indexing_order'] === 'fifo') {
$update
->condition('status', self::STATUS_INDEXED);
}
$update
->execute();
}
} catch (\Exception $e) {
$this
->logException($e);
}
}
public function trackAllItemsUpdated($datasource_id = NULL) {
try {
$update = $this
->createUpdateStatement();
$update
->fields([
'changed' => $this
->getTimeService()
->getRequestTime(),
'status' => $this::STATUS_NOT_INDEXED,
]);
if ($datasource_id) {
$update
->condition('datasource', $datasource_id);
}
$update
->execute();
} catch (\Exception $e) {
$this
->logException($e);
}
}
public function trackItemsIndexed(array $ids) {
try {
$ids_chunks = array_chunk($ids, 1000);
foreach ($ids_chunks as $ids_chunk) {
$update = $this
->createUpdateStatement();
$update
->fields([
'status' => $this::STATUS_INDEXED,
]);
$update
->condition('item_id', $ids_chunk, 'IN');
$update
->execute();
}
} catch (\Exception $e) {
$this
->logException($e);
}
}
public function trackItemsDeleted(array $ids = NULL) {
try {
$ids_chunks = $ids !== NULL ? array_chunk($ids, 1000) : [
NULL,
];
foreach ($ids_chunks as $ids_chunk) {
$delete = $this
->createDeleteStatement();
if ($ids_chunk) {
$delete
->condition('item_id', $ids_chunk, 'IN');
}
$delete
->execute();
}
} catch (\Exception $e) {
$this
->logException($e);
}
}
public function trackAllItemsDeleted($datasource_id = NULL) {
try {
$delete = $this
->createDeleteStatement();
if ($datasource_id) {
$delete
->condition('datasource', $datasource_id);
}
$delete
->execute();
} catch (\Exception $e) {
$this
->logException($e);
}
}
public function getRemainingItems($limit = -1, $datasource_id = NULL) {
try {
$select = $this
->createRemainingItemsStatement($datasource_id);
if ($limit >= 0) {
$select
->range(0, $limit);
}
return $select
->execute()
->fetchCol();
} catch (\Exception $e) {
$this
->logException($e);
return [];
}
}
public function getTotalItemsCount($datasource_id = NULL) {
try {
$select = $this
->createSelectStatement();
if ($datasource_id) {
$select
->condition('datasource', $datasource_id);
}
return (int) $select
->countQuery()
->execute()
->fetchField();
} catch (\Exception $e) {
$this
->logException($e);
return 0;
}
}
public function getIndexedItemsCount($datasource_id = NULL) {
try {
$select = $this
->createSelectStatement();
$select
->condition('sai.status', $this::STATUS_INDEXED);
if ($datasource_id) {
$select
->condition('datasource', $datasource_id);
}
return (int) $select
->countQuery()
->execute()
->fetchField();
} catch (\Exception $e) {
$this
->logException($e);
return 0;
}
}
public function getRemainingItemsCount($datasource_id = NULL) {
try {
$select = $this
->createRemainingItemsStatement();
if ($datasource_id) {
$select
->condition('datasource', $datasource_id);
}
return (int) $select
->countQuery()
->execute()
->fetchField();
} catch (\Exception $e) {
$this
->logException($e);
return 0;
}
}
}