Acest lucru este posibil cu procesoare personalizate search_api.
Mai întâi, am creat o clasă abstractă pe care să o folosesc ca bază pentru funcționalitatea partajată. i.e. o metodă de indexare a datelor unei entități arbitrare cu o bucată de conținut.
spațiu de nume Drupal\my_module\Plugin\search_api\processor;
utilizați Drupal\Core\Entity\ContentEntityInterface;
utilizați Drupal\search_api\Datasource\DatasourceInterface;
utilizați Drupal\search_api\Item\ItemInterface;
utilizați Drupal\search_api\Processor\EntityProcessorProperty;
utilizați Drupal\search_api\Processor\ProcessorPluginBase;
utilizați Drupal\search_api\Utility\Utility;
/**
* Clasa de plugin de bază pentru indexarea datelor despre entități legate în mod arbitrar.
*
* Acest lucru poate fi util pentru a indexa proprietățile entităților care fac referire la o entitate sau
* entități legate într-un alt mod arbitrar.
*
* @pachet Drupal\my_module\Plugin\search_api\processor
*/
clasa abstractă RelatedEntityBase extinde ProcessorPluginBase {
/**
* {@inheritdoc}
*/
funcția publică getPropertyDefinitions(DatasourceInterface $datasource = NULL) {
$plugin_definition = $this->getPluginDefinition();
$proprietati = [];
if (!$datasource || $datasource->getEntityTypeId() !== $this->getIndexedEntityTypeId()) {
returnează $proprietăți;
}
$definiție = [
'label' => $plugin_definition['label'],
'description' => $plugin_definition['descriere'],
'type' => 'entitate:' . $this->getRelatedEntityTypeId(),
'processor_id' => $this->getPluginId(),
'is_list' => TRUE,
];
$property = new EntityProcessorProperty($definition);
$property->setEntityTypeId($this->getRelatedEntityTypeId());
$properties[$this->getPluginId()] = $proprietate;
returnează $proprietăți;
}
/**
* {@inheritdoc}
*/
funcția publică addFieldValues(ItemInterface $item) {
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $item->getOriginalObject()->getValue();
$pentru_extrage = [];
foreach ($item->getFields() ca $câmp) {
$datasource = $field->getDatasource();
$cale_proprietate = $câmp->getPropertyPath();
[$direct, $imbricat] = Utility::splitPropertyPath($property_path, FALSE);
if ($datasource && $datasource->getEntityTypeId() === $entity->getEntityTypeId() && $direct === $this->getPluginId()) {
$to_extract[$imbricat][] = $câmp;
}
}
foreach ($this->getRelatedEntities($entity) ca $relation) {
$this->getFieldsHelper()
->extractFields($relation->getTypedData(), $to_extract, $item->getLanguage());
}
}
/**
* Obțineți o serie de entități conexe.
*
* Aceasta ar trebui să returneze o serie de entități complet încărcate care se referă la
* $entity este indexat.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* Entitatea care este indexată.
*
* @return matrice
* O serie de entități legate de $entity.
*/
funcţie abstractă protejată getRelatedEntities(ContentEntityInterface $entity): matrice;
/**
* Obțineți ID-ul tipului de entitate al entității care este indexată.
*
* Acesta este tipul de entitate al entității $ căreia i-a fost transmis
* $this->getRelatedEntities().
*
* @return șir
* Un șir de id de tip de entitate, de ex. „nod”, „media” sau „termen_taxonomie”.
*/
funcție abstractă protejată getIndexedEntityTypeId(): șir;
/**
* Obțineți ID-ul tipului de entitate al entităților aferente.
*
* Acesta este tipul de entitate de la articolele returnate
* $this->getRelatedEntities().
*
* @return șir
* Un șir de id de tip de entitate, de ex. „nod”, „media” sau „termen_taxonomie”.
*/
funcție abstractă protejată getRelatedEntityTypeId(): șir;
}
Apoi, am creat clase de plugin care mi-au extins clasa abstractă pentru fiecare caz (Autorii colecției, Colecțiile articolelor, Colecțiile autorului). De exemplu, pentru a indexa datele din colecțiile unui articol ca parte a datelor indexate ale articolului:
spațiu de nume Drupal\my_module\Plugin\search_api\processor;
utilizați Drupal\Core\Entity\ContentEntityInterface;
utilizați Drupal\my_module\Plugin\search_api\processor\RelatedEntityBase;
/**
* Indexați proprietățile din colecții care fac referire la un articol.
*
* @SearchApiProcessor(
* id = „colecțiile_mii_module_articole”,
* label = @Translation ("Colecțiile articolului"),
* description = @Translation(„Proprietățile indexate din colecții care fac referire la acest articol.”),
* etape = {
* „add_properties” = 0,
*},
* )
*/
clasa ArticleCollections extinde RelatedEntityBase {
/**
* {@inheritdoc}
*/
funcția protejată getRelatedEntities(ContentEntityInterface $entity): array {
returnează my_function_to_get_article_collections($entity)
}
/**
* {@inheritdoc}
*/
funcție protejată getIndexedEntityTypeId(): șir {
returnează „nod”;
}
/**
* {@inheritdoc}
*/
funcție protejată getRelatedEntityTypeId(): șir {
returnează „nod”;
}
}
Acest lucru mi-a permis să indexez datele dintr-o colecție ca parte a datelor unui articol, de exemplu ID-urile colecției articolului (adică ID-urile colecțiilor care fac referire la articol). Pot indexa orice câmp din Colecție - selectând câmpul pe care îl doresc în UI - la fel ca și când articolul ar avea un câmp de referință de entitate care face referire la Colecție. (Notă: înainte de a putea indexa orice câmp cu procesorul personalizat, trebuie mai întâi să îl activați în fila Procesor pentru indexul dvs.)
Toate acestea au funcționat excelent, cu toate acestea, datele mele indexate nu au rămas sincronizate cu realitatea. De exemplu, dacă aș adăuga un articol nou la o colecție, datele indexate pentru acel articol nou nu vor fi actualizate cu informații pentru noua colecție. i.e.articolul nu a fost reindexat dacă o colecție care face referire la el a fost actualizată. Am rezolvat asta cu a hook_ENTITY_TYPE_update() implementare care marchează articolele dependente pentru a fi reindexate atunci când o colecție este salvată.
utilizați Drupal\node\NodeInterface;
/*
* Implementează hook_ENTITY_TYPE_update().
*/
funcția my_module_node_update(NodeInterface $nod) {
if ($nod->bundle() == 'colecție') {
$articole = [];
// Adună toate articolele la care se referă această colecție.
$articole = my_function_to_get_collection_articles($nod);
// Adunați, de asemenea, orice articole la care au fost menționate înainte de această salvare, dar sunt
// nu se mai face referire.
$original_node = isset($node->original) ? $nod->original : NULL;
if ($original_node instanceof NodeInterface) {
$articole += my_function_to_get_collection_articles($original_node);
}
// Marcați articolele care urmează să fie reindexate.
foreach ($articole ca $articol) {
/** @var \Drupal\search_api\Plugin\search_api\datasource\ContentEntityTrackingManager $tracking_manager */
$search_api_tracking_manager = \Drupal::service('search_api.entity_datasource.tracking_manager');
$indexes = $search_api_tracking_manager->getIndexesForEntity($articol);
dacă (!gol ($indexuri)) {
$item_ids = [];
foreach ($articol->getTranslationLanguages() ca $langcode => $language) {
$articol_ids[] = $articol->id() . ':' . $langcode;
}
foreach ($indexuri ca $index) {
$index->trackItemsUpdated('entity:node', $item_ids);
}
}
}
}
}
După toate acestea, pot indexa în siguranță datele de la entități legate în mod arbitrar.