View source
<?php
declare (strict_types=1);
namespace Drupal\Tests\search_api\Kernel\Datasource;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\search_api\Entity\Index;
use Drupal\search_api\Entity\Server;
use Drupal\search_api\Utility\TrackingHelper;
use Drupal\search_api\Utility\Utility;
class ReferencedEntitiesReindexingTest extends KernelTestBase {
public static $modules = [
'user',
'node',
'field',
'system',
'search_api',
'search_api_test',
'search_api_test_example_content_references',
];
protected $index;
public function setUp() {
parent::setUp();
$this
->installSchema('search_api', [
'search_api_item',
]);
$this
->installSchema('node', [
'node_access',
]);
$this
->installEntitySchema('user');
$this
->installEntitySchema('node');
$this
->installEntitySchema('search_api_task');
$this
->installConfig([
'search_api',
'search_api_test_example_content_references',
]);
if (!Utility::isRunningInCli()) {
\Drupal::state()
->set('search_api_use_tracking_batch', FALSE);
}
Server::create([
'id' => 'server',
'backend' => 'search_api_test',
])
->save();
$this->index = Index::create([
'id' => 'index',
'tracker_settings' => [
'default' => [],
],
'datasource_settings' => [
'entity:node' => [
'bundles' => [
'default' => FALSE,
'selected' => [
'grandparent',
'parent',
],
],
],
'entity:user' => [],
],
'server' => 'server',
'field_settings' => [
'child_indexed' => [
'label' => 'Child > Indexed',
'datasource_id' => 'entity:node',
'property_path' => 'entity_reference:entity:indexed',
'type' => 'text',
],
'grandchild_indexed' => [
'label' => 'Parent > Child > Indexed',
'datasource_id' => 'entity:node',
'property_path' => 'parent_reference:entity:entity_reference:entity:indexed',
'type' => 'text',
],
],
]);
$this->index
->save();
}
public function testReferencedEntityChanged(array $child_map, array $updates, array $expected) {
$children = $this
->createEntitiesFromMap($child_map, [], 'child');
$parent_map = [
'parent' => [
'title' => 'Parent',
'entity_reference' => 'child',
],
];
$parents = $this
->createEntitiesFromMap($parent_map, $children, 'parent');
$grandparent_map = [
'grandparent' => [
'title' => 'Grandparent',
'parent_reference' => 'parent',
],
];
$this
->createEntitiesFromMap($grandparent_map, $parents, 'grandparent');
$this->index
->indexItems();
$tracker = $this->index
->getTrackerInstance();
$this
->assertEquals([], $tracker
->getRemainingItems());
foreach ($updates as $i => $field_updates) {
if ($field_updates === FALSE) {
$children[$i]
->delete();
}
else {
foreach ($field_updates as $field => $items) {
$children[$i]
->get($field)
->setValue($items);
}
$children[$i]
->save();
}
}
$this
->assertEquals($expected, $tracker
->getRemainingItems());
}
public function referencedEntityChangedDataProvider() : array {
$parents_expected = [
'entity:node/3:en',
'entity:node/4:en',
];
$child_variants = [
'child',
'unrelated',
];
$field_variants = [
'indexed',
'not_indexed',
];
$tests = [];
foreach ($child_variants as $child) {
foreach ($field_variants as $field) {
if ($child == 'child' && $field == 'indexed') {
$expected = $parents_expected;
}
else {
$expected = [];
}
$tests["changing value of {$field} field within the {$child} entity"] = [
[
'child' => [
'title' => 'Child',
'indexed' => 'Original indexed value',
'not_indexed' => 'Original not indexed value.',
],
'unrelated' => [
'title' => 'Unrelated child',
'indexed' => 'Original indexed value',
'not_indexed' => 'Original not indexed value.',
],
],
[
$child => [
$field => "New {$field} value.",
],
],
$expected,
];
$tests["appending value of {$field} field within the {$child} entity"] = [
[
'child' => [
'title' => 'Child',
'indexed' => 'Original indexed value',
],
'unrelated' => [
'title' => 'Unrelated child',
'indexed' => 'Original indexed value',
],
],
[
$child => [
$field => "New {$field} value.",
],
],
$expected,
];
$tests["removing value of {$field} field within the {$child} entity"] = [
[
'child' => [
'title' => 'Child',
'indexed' => 'Original indexed value',
'not_indexed' => 'Original not indexed value.',
],
'unrelated' => [
'title' => 'Unrelated child',
'indexed' => 'Original indexed value',
'not_indexed' => 'Original not indexed value.',
],
],
[
$child => [
$field => [],
],
],
$expected,
];
}
$tests["removing the {$child} entity"] = [
[
'child' => [
'title' => 'Child',
'indexed' => 'Original indexed value',
'not_indexed' => 'Original not indexed value.',
],
'unrelated' => [
'title' => 'Unrelated child',
'indexed' => 'Original indexed value',
'not_indexed' => 'Original not indexed value.',
],
],
[
$child => FALSE,
],
$child == 'child' ? $parents_expected : [],
];
}
return $tests;
}
protected function createEntitiesFromMap(array $entity_fields, array $references_map, string $bundle) : array {
$entities = [];
foreach ($entity_fields as $i => $fields) {
$reference_fields = [
'entity_reference',
'parent_reference',
];
foreach ($reference_fields as $reference_field) {
if (isset($fields[$reference_field])) {
$fields[$reference_field] = $references_map[$fields[$reference_field]]
->id();
}
}
$fields['type'] = $bundle;
$entities[$i] = Node::create($fields);
$entities[$i]
->save();
}
return $entities;
}
public function testUnrelatedDatasourceUnaffected() {
$tracking_helper = \Drupal::getContainer()
->get('search_api.tracking_helper');
$method = new \ReflectionMethod(TrackingHelper::class, 'getForeignEntityRelationsMap');
$method
->setAccessible(TRUE);
$map = $method
->invoke($tracking_helper, $this->index);
usort($map, function (array $a, array $b) : int {
$field = 'property_path_to_foreign_entity';
return $a[$field] <=> $b[$field];
});
$expected = [
[
'datasource' => 'entity:node',
'entity_type' => 'node',
'bundles' => [
'child' => 'child',
],
'property_path_to_foreign_entity' => 'entity_reference:entity',
'field_name' => 'indexed',
],
[
'datasource' => 'entity:node',
'entity_type' => 'node',
'bundles' => [
'parent' => 'parent',
],
'property_path_to_foreign_entity' => 'parent_reference:entity',
'field_name' => 'entity_reference',
],
[
'datasource' => 'entity:node',
'entity_type' => 'node',
'bundles' => [
'child' => 'child',
],
'property_path_to_foreign_entity' => 'parent_reference:entity:entity_reference:entity',
'field_name' => 'indexed',
],
];
$this
->assertEquals($expected, $map);
$datasource = $this->index
->getDatasource('entity:user');
$entities = $this
->createEntitiesFromMap([
'child' => [
'title' => 'Child',
'indexed' => 'Indexed value',
'not_indexed' => 'Not indexed value.',
],
], [], 'child');
$child = reset($entities);
$original_child = clone $child;
$child
->get('indexed')
->setValue([
'New value',
]);
$result = $datasource
->getAffectedItemsForEntityChange($child, $map, $original_child);
$this
->assertEquals([], $result);
$map[0]['property_path_to_foreign_entity'] = 'entity_reference:entity';
$result = $datasource
->getAffectedItemsForEntityChange($child, $map, $original_child);
$this
->assertEquals([], $result);
}
}