Commit bbb9cf7b authored by borisson_'s avatar borisson_ Committed by StryKaizer

Issue #2851851 by borisson_, edurenye, StryKaizer: Facet source plugins should...

Issue #2851851 by borisson_, edurenye, StryKaizer: Facet source plugins should provide metadata for facet fields
parent 888290d8
......@@ -530,6 +530,13 @@ class Facet extends ConfigEntityBase implements FacetInterface {
return $this->hard_limit ?: 0;
}
/**
* {@inheritdoc}
*/
public function getDataDefinition() {
return $this->getFacetSource()->getDataDefinition($this->field_identifier);
}
/**
* {@inheritdoc}
*/
......
......@@ -204,6 +204,14 @@ interface FacetInterface extends ConfigEntityInterface {
*/
public function getHardLimit();
/**
* Returns the data definition from the facet field.
*
* @return \Drupal\Core\TypedData\DataDefinitionInterface
* A typed data definition.
*/
public function getDataDefinition();
/**
* Returns the value of the exclude boolean.
*
......
......@@ -97,4 +97,12 @@ interface FacetSourcePluginInterface extends PluginFormInterface, DependentPlugi
*/
public function getSearchKeys();
/**
* Returns a single field's data definition from the facet source.
*
* @return \Drupal\Core\TypedData\DataDefinitionInterface
* A typed data definition.
*/
public function getDataDefinition($field_name);
}
......@@ -5,6 +5,7 @@ namespace Drupal\facets\Plugin\facets\facet_source;
use Drupal\Component\Plugin\DependentPluginInterface;
use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\Form\FormStateInterface;
use Drupal\facets\Exception\Exception;
use Drupal\facets\Exception\InvalidQueryTypeException;
use Drupal\facets\FacetInterface;
use Drupal\facets\FacetSource\FacetSourcePluginBase;
......@@ -360,4 +361,15 @@ class SearchApiDisplay extends FacetSourcePluginBase implements SearchApiFacetSo
return $view;
}
/**
* {@inheritdoc}
*/
public function getDataDefinition($field_name) {
$field = $this->getIndex()->getField($field_name);
if ($field) {
return $field->getDataDefinition();
}
throw new Exception("Field with name {$field_name} does not have a definition");
}
}
......@@ -106,7 +106,7 @@ class ListItemProcessor extends ProcessorPluginBase implements BuildProcessorInt
$field = $index->getField($field_identifier);
if (!$field->getDatasourceId()) {
throw new InvalidProcessorException("The {$field_identifier} field has no datasource, there is no valid use for the {$this->pluginId} processor with this facet");
throw new InvalidProcessorException("This field has no datasource, there is no valid use for this processor with this facet");
}
$entity = $field->getDatasource()->getEntityTypeId();
}
......
......@@ -5,9 +5,10 @@ namespace Drupal\facets\Plugin\facets\processor;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\TypedData\DataReferenceDefinitionInterface;
use Drupal\Core\TypedData\TranslatableInterface;
use Drupal\facets\Exception\InvalidProcessorException;
use Drupal\facets\FacetInterface;
use Drupal\facets\Plugin\facets\facet_source\SearchApiDisplay;
use Drupal\facets\Processor\BuildProcessorInterface;
use Drupal\facets\Processor\ProcessorPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -80,33 +81,30 @@ class TranslateEntityProcessor extends ProcessorPluginBase implements BuildProce
public function build(FacetInterface $facet, array $results) {
$language_interface = $this->languageManager->getCurrentLanguage();
$ids = [];
/** @var \Drupal\Core\TypedData\DataDefinitionInterface $data_definition */
$data_definition = $facet->getDataDefinition();
/** @var \Drupal\facets\Result\ResultInterface $result */
foreach ($results as $delta => $result) {
$ids[$delta] = $result->getRawValue();
$property = NULL;
foreach ($data_definition->getPropertyDefinitions() as $k => $definition) {
if ($definition instanceof DataReferenceDefinitionInterface && $definition->getDataType() === 'entity_reference') {
$property = $k;
break;
}
}
// Default to nodes.
$entity_type = 'node';
$source = $facet->getFacetSource();
// Support multiple entity types when using Search API.
if ($source instanceof SearchApiDisplay) {
$field_id = $facet->getFieldIdentifier();
if ($property === NULL) {
throw new InvalidProcessorException("Field doesn't have an entity definition, so this processor doesn't work.");
}
// Load the index from the source, load the definition from the
// datasource.
/** @var \Drupal\facets\FacetSource\SearchApiFacetSourceInterface $source */
$index = $source->getIndex();
$field = $index->getField($field_id);
$entity_type = $data_definition
->getPropertyDefinition($property)
->getTargetDefinition()
->getEntityTypeId();
// Determine the target entity type.
$entity_type = $field->getDataDefinition()
->getPropertyDefinition('entity')
->getTargetDefinition()
->getEntityTypeId();
/** @var \Drupal\facets\Result\ResultInterface $result */
$ids = [];
foreach ($results as $delta => $result) {
$ids[$delta] = $result->getRawValue();
}
// Load all indexed entities of this type.
......
......@@ -2,10 +2,12 @@
namespace Drupal\Tests\facets\Kernel\Entity;
use Drupal\Core\TypedData\DataDefinitionInterface;
use Drupal\facets\Entity\Facet;
use Drupal\facets\FacetSourceInterface;
use Drupal\facets\Plugin\facets\facet_source\SearchApiDisplay;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\facets\Exception\Exception;
/**
* Class FacetFacetSourceTest.
......@@ -129,4 +131,24 @@ class FacetFacetSourceTest extends EntityKernelTestBase {
$this->assertEquals('search_api_string', $aa);
}
/**
* Test the data definitions.
*
* @covers \Drupal\facets\FacetSource\FacetSourcePluginInterface::getDataDefinition
*/
public function testDataDefinitions() {
// Create and configure facet.
$entity = new Facet([], 'facets_facet');
$display_name = 'search_api:views_page__search_api_test_view__page_1';
$entity->setFacetSourceId($display_name);
$this->assertInstanceOf(DataDefinitionInterface::class, $entity->getFacetSource()->getDataDefinition('id'));
$this->assertInstanceOf(DataDefinitionInterface::class, $entity->getFacetSource()->getDataDefinition('name'));
$this->assertInstanceOf(DataDefinitionInterface::class, $entity->getFacetSource()->getDataDefinition('category'));
// When trying to get a field that doesn't exist, an error should be thrown.
$this->setExpectedException(Exception::class);
$entity->getFacetSource()->getDataDefinition('llama');
}
}
......@@ -2,8 +2,12 @@
namespace Drupal\Tests\facets\Unit\Plugin\processor;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\EntityTypeBundleInfo;
use Drupal\Core\TypedData\ComplexDataDefinitionInterface;
use Drupal\facets\Entity\Facet;
use Drupal\facets\FacetSource\FacetSourcePluginInterface;
use Drupal\facets\FacetSource\FacetSourcePluginManager;
use Drupal\facets\Plugin\facets\processor\ListItemProcessor;
use Drupal\facets\Result\Result;
use Drupal\field\Entity\FieldStorageConfig;
......@@ -58,7 +62,35 @@ class ListItemProcessorTest extends UnitTestCase {
->disableOriginalConstructor()
->getMock();
// Create a search api based facet source and make the property definition
// return null.
$data_definition = $this->getMock(ComplexDataDefinitionInterface::class);
$data_definition->expects($this->any())
->method('getPropertyDefinition')
->willReturn(NULL);
$facet_source = $this->getMockBuilder(FacetSourcePluginInterface::class)
->disableOriginalConstructor()
->getMock();
$facet_source->expects($this->any())
->method('getDataDefinition')
->willReturn($data_definition);
// Add the plugin manager.
$pluginManager = $this->getMockBuilder(FacetSourcePluginManager::class)
->disableOriginalConstructor()
->getMock();
$pluginManager->expects($this->any())
->method('hasDefinition')
->willReturn(TRUE);
$pluginManager->expects($this->any())
->method('createInstance')
->willReturn($facet_source);
$this->processor = new ListItemProcessor([], 'list_item', [], $config_manager, $entity_field_manager, $entity_type_bundle_info);
$container = new ContainerBuilder();
$container->set('plugin.manager.facets.facet_source', $pluginManager);
\Drupal::setContainer($container);
}
/**
......@@ -91,12 +123,14 @@ class ListItemProcessorTest extends UnitTestCase {
// Config entity field facet.
$module_field_facet = new Facet([], 'facets_facet');
$module_field_facet->setFieldIdentifier('test_facet');
$module_field_facet->setFacetSourceId('llama_source');
$module_field_facet->setResults($this->results);
$module_field_facet->addProcessor([
'processor_id' => 'list_item',
'weights' => [],
'settings' => [],
]);
/* @var \Drupal\facets\Result\Result[] $module_field_facet- */
$module_field_results = $processor->build($module_field_facet, $this->results);
......@@ -134,6 +168,7 @@ class ListItemProcessorTest extends UnitTestCase {
// Config entity field facet.
$module_field_facet = new Facet([], 'facets_facet');
$module_field_facet->setFieldIdentifier('test_facet');
$module_field_facet->setFacetSourceId('llama_source');
$module_field_facet->setResults($this->results);
$module_field_facet->addProcessor([
'processor_id' => 'list_item',
......@@ -180,6 +215,7 @@ class ListItemProcessorTest extends UnitTestCase {
// Base prop facet.
$base_prop_facet = new Facet([], 'facets_facet');
$base_prop_facet->setFieldIdentifier('test_facet_baseprop');
$base_prop_facet->setFacetSourceId('llama_source');
$base_prop_facet->setResults($this->results);
$base_prop_facet->addProcessor([
'processor_id' => 'list_item',
......
......@@ -10,12 +10,9 @@ use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\TypedData\ComplexDataDefinitionInterface;
use Drupal\Core\TypedData\DataReferenceDefinitionInterface;
use Drupal\facets\Entity\Facet;
use Drupal\facets\Plugin\facets\facet_source\SearchApiDisplay;
use Drupal\facets\Plugin\facets\processor\TranslateEntityProcessor;
use Drupal\facets\Result\Result;
use Drupal\node\Entity\Node;
use Drupal\search_api\IndexInterface;
use Drupal\search_api\Item\FieldInterface;
use Drupal\taxonomy\Entity\Term;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
......@@ -70,40 +67,25 @@ class TranslateEntityProcessorTest extends UnitTestCase {
$property_definition->expects($this->any())
->method('getTargetDefinition')
->willReturn($target_field_definition);
$property_definition->expects($this->any())
->method('getDataType')
->willReturn('entity_reference');
$data_definition = $this->getMock(ComplexDataDefinitionInterface::class);
$data_definition->expects($this->any())
->method('getPropertyDefinition')
->willReturn($property_definition);
// Add the typed data definition to the search api field.
$field = $this->getMock(FieldInterface::class);
$field->expects($this->any())
->method('getDataDefinition')
->willReturn($data_definition);
// Add the search api field to the index.
$index = $this->getMock(IndexInterface::class);
$index->expects($this->any())
->method('getField')
->willReturn($field);
// Create a search api based facet source and link the index to it.
$facet_source = $this->getMockBuilder(SearchApiDisplay::class)
->disableOriginalConstructor()
->getMock();
$facet_source->expects($this->any())
->method('getIndex')
->willReturn($index);
$data_definition->expects($this->any())
->method('getPropertyDefinitions')
->willReturn([$property_definition]);
// Create the actual facet.
$this->facet = $this->getMockBuilder(Facet::class)
->disableOriginalConstructor()
->getMock();
// Return the configured facet source.
$this->facet->expects($this->any())
->method('getFacetSource')
->willReturn($facet_source);
->method('getDataDefinition')
->willReturn($data_definition);
// Add a field identifier.
$this->facet->expects($this->any())
->method('getFieldIdentifier')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment