2

I have a site with 14 pieces of news and 44 basic pages.

  1. I have created an index (Search API) with this bundle: enter image description here

and this is the index status (the content is already indexed during cron): enter image description here

  1. When I edit the config, add the Basic page bundle and save it: enter image description here

The index status is updated: enter image description here

I want to do the part 2 programmatically. I tried two ways:

$index = Index::load('my_index');
$index->setOption('datasource_settings', [
  'entity:node' => [
    'bundles' => [
      'default' => 0,
      'selected' => ['news', 'page'],
      'languages' => [
        'default' => 1',
        'selected' => [ ],
      ],
    ]
  ],
]);
$index->save();

and

$datasource_settings = [
  'entity:node' => [
    'bundles' => [
      'default' => 0,
      'selected' => ['news', 'page'],
      'languages' => [
        'default' => 'TRUE',
        'selected' => [ ],
      ],
    ]
  ],
];
$search_index = \Drupal::configFactory()->getEditable('search_api.index.my_index');
$search_index->set('datasource_settings', $datasource_settings)->save();

The config is saved, but the status index is not updated: enter image description here

I tried to use these codes:

Option 1:

$index = Index::load('my_index');
$index->reindex();

But the nodes number are not updated, and I lose the nodes indexed: enter image description here

Option 2:

$index = Index::load('my_index');
$index->rebuildTracker();

Result: enter image description here

Option 3:

$index = Index::load('my_index');
$index->clear();

Result: enter image description here

So my question is: How to update an index config programmatically and get the index status updated like the UI does when you click the Save button. I tried to look inside the search_api module code, but I got lost :(

Thank you in advance.

7
  • As the search index is a config item you could try updating the config for it programatically drupal.org/docs/drupal-apis/update-api/… Commented Feb 23, 2023 at 17:08
  • @unusedspoon I tried it like that, but the index status does not update well, and it shows old information, I can fix it reindexing/clearing the index, or rebuilding track information, but I don't want to lose the indexed items.
    – rpayanm
    Commented Feb 23, 2023 at 17:30
  • 1
    What are you trying to do exactly? If you are updating config, usually you load it from its config factory by its ID.
    – Kevin
    Commented Feb 24, 2023 at 0:55
  • @Kevin I updated the question.
    – rpayanm
    Commented Feb 27, 2023 at 14:34
  • 1
    I still don't understand what the point of this is. There are a variety of Drush commands for search API to index, clear, etc. I also don't see any explanation of why you are changing configuration programmatically or not using the config factory interface.
    – Kevin
    Commented Feb 27, 2023 at 14:51

2 Answers 2

2

You can update the configuration of the search index with the following code

use Drupal\search_api\Entity\Index;

$index = Index::load('my_index');
$datasources = $index->getDatasources();
foreach ($datasources as $datasource_id => $datasource) {
  if ($datasource_id == 'entity:node') {
    $configuration = $datasource->getConfiguration();
    // This will add the 'page' bundle to the configuration.
    $configuration['bundles']['selected'][] = 'page';
    $datasources[$datasource_id]->setConfiguration($configuration);
  }
}
$index->save();

After saving the index, automatically a batch process will be called, if the changes are submitted in a form. Otherwise you manually need to add the new items to the index or reindex the whole index. For manually adding the new items, you can for example use the following code

$tracker = $index->getTrackerInstance();
$entity_type_manager = \Drupal::entityTypeManager();
$node_storage = $entity_type_manager->getStorage('node');
// Get the IDs of the new items.
$query = $node_storage->getQuery();
$query->condition('type', 'page');
$new_ids = $query->execute();
$entities = $node_storage->loadMultiple($new_ids);
$content_entity_tracking_manager = \Drupal::service('search_api.entity_datasource.tracking_manager');
foreach ($entities as $entity) {
  // Index the newly added item.
  $content_entity_tracking_manager->entityInsert($entity);
}

This may only works if you just have a few hundred new nodes, because you otherwise will get a timeout. Thats the reason, why the indexing happens in the batch process.

0

To reindex items as it's done through the UI, you can do the following (but this won't queue the action so it can be super slow and you should avoid calling it inside a controller action for example):

$index = Index::load('my_index');
$index->reindex();

$datasource_ids = $index->getDatasourceIds();

foreach ($datasource_ids as $datasource_id) {
    // The method returns the number of indexed elements if needed.
    $index->indexItems(-1, $datasource_id);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.