diff --git a/src/Plugin/search_api/processor/SearchApiExcludeEntityProcessor.php b/src/Plugin/search_api/processor/SearchApiExcludeEntityProcessor.php index 51a8cbc..db8fd30 100644 --- a/src/Plugin/search_api/processor/SearchApiExcludeEntityProcessor.php +++ b/src/Plugin/search_api/processor/SearchApiExcludeEntityProcessor.php @@ -2,6 +2,7 @@ namespace Drupal\search_api_exclude_entity\Plugin\search_api\processor; +use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\PluginFormInterface; use Drupal\search_api\Plugin\PluginFormTrait; @@ -24,7 +25,12 @@ class SearchApiExcludeEntityProcessor extends ProcessorPluginBase implements Plu use PluginFormTrait; - protected $entity_manager; + /** + * The entity field manager. + * + * @var \Drupal\Core\Entity\EntityFieldManagerInterface|null + */ + protected $entityFieldManager; /** * {@inheritdoc} @@ -32,11 +38,36 @@ class SearchApiExcludeEntityProcessor extends ProcessorPluginBase implements Plu public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { /** @var static $processor */ $processor = parent::create($container, $configuration, $plugin_id, $plugin_definition); - $processor->entity_manager = $container->get('entity.manager'); + + $processor->setEntityFieldManager($container->get('entity_field.manager')); + return $processor; } /** + * Retrieves the entity field manager. + * + * @return \Drupal\Core\Entity\EntityFieldManagerInterface + * The entity field manager. + */ + public function getEntityFieldManager() { + return $this->entityFieldManager ?: \Drupal::service('entity_field.manager'); + } + + /** + * Sets the entity field manager. + * + * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager + * The new entity field manager. + * + * @return $this + */ + public function setEntityFieldManager(EntityFieldManagerInterface $entity_field_manager) { + $this->entityFieldManager = $entity_field_manager; + return $this; + } + + /** * {@inheritdoc} */ public function defaultConfiguration() { @@ -97,7 +128,7 @@ class SearchApiExcludeEntityProcessor extends ProcessorPluginBase implements Plu * Options array with bundles. */ private function getFieldOptions($entity_type, $datasource) { - $field_map = $this->entity_manager->getFieldMapByFieldType('search_api_exclude_entity'); + $field_map = $this->getEntityFieldManager()->getFieldMapByFieldType('search_api_exclude_entity'); $bundles = $datasource->getBundles(); $options = array(); @@ -132,14 +163,14 @@ class SearchApiExcludeEntityProcessor extends ProcessorPluginBase implements Plu * @param string $field * The field we are checking if it is being used by the bundle. * - * @return array - * Options array with bundles. + * @return bool + * TRUE if the entity bundle has the field, FALSE otherwise. */ private function bundleHasField($entity_type, $bundle, $field) { static $field_map; if (!isset($field_map)) { - $field_map = $this->entity_manager->getFieldMapByFieldType('search_api_exclude_entity'); + $field_map = $this->getEntityFieldManager()->getFieldMapByFieldType('search_api_exclude_entity'); } return isset($field_map[$entity_type][$field]['bundles'][$bundle]); diff --git a/tests/src/Unit/Processor/SearchApiExcludeEntityProcessorTest.php b/tests/src/Unit/Processor/SearchApiExcludeEntityProcessorTest.php new file mode 100644 index 0000000..084fc65 --- /dev/null +++ b/tests/src/Unit/Processor/SearchApiExcludeEntityProcessorTest.php @@ -0,0 +1,198 @@ +setUpMockContainer(); + + $this->fieldsHelper = \Drupal::getContainer()->get('search_api.fields_helper'); + $this->index = $this->createMock(IndexInterface::class); + + $this->excludeEnabledValue = $this->createMock(FieldItemListInterface::class); + $this->excludeEnabledValue->method('getValue') + ->willReturn([0 => ['value' => '1']]); + $this->excludeDisabledValue = $this->createMock(FieldItemListInterface::class); + $this->excludeDisabledValue->method('getValue') + ->willReturn([0 => ['value' => '0']]); + + // Node type 'article' has two exclude fields. + $entity_field_manager = $this->createMock(EntityFieldManagerInterface::class); + $entity_field_manager->method('getFieldMapByFieldType') + ->with('search_api_exclude_entity') + ->willReturn([ + 'node' => [ + $this->fieldName1 => [ + 'type' => 'search_api_exclude_entity', + 'bundles' => ['article' => 'article'], + ], + $this->fieldName2 => [ + 'type' => 'search_api_exclude_entity', + 'bundles' => ['article' => 'article'], + ], + ], + ]); + + $configuration['fields']['node'] = [ + $this->fieldName1, + $this->fieldName2 + ]; + + /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */ + $this->processor = new SearchApiExcludeEntityProcessor($configuration, 'search_api_exclude_entity_processor', []); + $this->processor->setEntityFieldManager($entity_field_manager); + } + + /** + * Helper function for creating node based mock search index items. + * + * @param string $bundle + * The bundle name of the mock node. + * @param string $raw_id + * The raw ID of the mock search index item. + * @param \Drupal\Core\Field\FieldItemListInterface $field_value_1 + * (Optional) The value of the first exclude field of the mock node. + * @param \Drupal\Core\Field\FieldItemListInterface $field_value_2 + * (Optional) The value of the second exclude field of the mock node. + * + * @return \Drupal\search_api\Item\ItemInterface + */ + protected function createMockItem($bundle, $raw_id, $field_value_1 = NULL, $field_value_2 = NULL) { + $node = $this->createMock(NodeInterface::class); + $node->method('getEntityTypeId')->willReturn('node'); + $node->method('bundle')->willReturn($bundle); + + $node->method('get') + ->will($this->returnValueMap([ + [$this->fieldName1, $field_value_1], + [$this->fieldName2, $field_value_2], + ])); + + /** @var \Drupal\search_api\Item\ItemInterface $item */ + /** @var \Drupal\node\NodeInterface $node */ + $id = Utility::createCombinedId('entity:node', $raw_id); + $item = $this->fieldsHelper->createItem($this->index, $id); + $item->setOriginalObject(EntityAdapter::createFromEntity($node)); + + return $item; + } + + /** + * Tests altering the indexed items. + * + * @covers ::alterIndexedItems + */ + public function testAlterIndexedItems() { + $item1 = $this->createMockItem( + 'page', + '1:en' + ); + $item2 = $this->createMockItem( + 'article', + '2:en', + $this->excludeDisabledValue, + $this->excludeDisabledValue + ); + $item3 = $this->createMockItem( + 'article', + '3:en', + $this->excludeDisabledValue, + $this->excludeEnabledValue + ); + $item4 = $this->createMockItem( + 'article', + '4:en', + $this->excludeEnabledValue, + $this->excludeEnabledValue + ); + + $items = [ + $item1->getId() => $item1, + $item2->getId() => $item2, + $item3->getId() => $item3, + $item4->getId() => $item4, + ]; + + $this->processor->alterIndexedItems($items); + + $this->assertTrue(!empty($items[$item1->getId()]), "Item without any exclude fields wasn't removed."); + $this->assertTrue(!empty($items[$item2->getId()]), "Item with 0/2 of exclude fields enabled wasn't removed."); + $this->assertTrue(empty($items[$item3->getId()]), "Item with 1/2 of exclude fields enabled was removed."); + $this->assertTrue(empty($items[$item4->getId()]), "Item with 2/2 of exclude fields enabled was removed."); + } +}