diff --git a/src/Plugin/search_api/processor/AddHierarchy.php b/src/Plugin/search_api/processor/AddHierarchy.php index d338e97..77f1026 100644 --- a/src/Plugin/search_api/processor/AddHierarchy.php +++ b/src/Plugin/search_api/processor/AddHierarchy.php @@ -4,9 +4,9 @@ use Drupal\Component\Utility\Html; use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface; -use Drupal\Core\Field\TypedData\FieldItemDataDefinition; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\PluginFormInterface; use Drupal\Core\TypedData\ComplexDataDefinitionInterface; @@ -14,7 +14,6 @@ use Drupal\search_api\Item\FieldInterface; use Drupal\search_api\Plugin\PluginFormTrait; use Drupal\search_api\Processor\ProcessorPluginBase; -use Drupal\search_api\Utility\Utility; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -48,6 +47,13 @@ class AddHierarchy extends ProcessorPluginBase implements PluginFormInterface { protected $entityTypeManager; /** + * The entity field manager. + * + * @var \Drupal\Core\Entity\EntityFieldManagerInterface|null + */ + protected $entityFieldManager; + + /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { @@ -83,6 +89,29 @@ public function setEntityTypeManager(EntityTypeManagerInterface $entity_type_man } /** + * 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 static function supportsIndex(IndexInterface $index) { @@ -115,11 +144,23 @@ protected function getHierarchyFields() { $properties = $definition->getPropertyDefinitions(); // The property might be an entity data definition itself. $properties[''] = $definition; + // Unfortunately, Core fails to correctly pass down an entity + // reference field's configured bundles to its "entity" sub-property, + // which means that only references that are base fields would be + // found. We therefore have to manually include the appropriate + // bundles in our code. + $bundles = array(); + if ($definition->getDataType() === 'field_item:entity_reference') { + $settings = $definition->getSettings(); + if (!empty($settings['handler_settings']['target_bundles'])) { + $bundles = $settings['handler_settings']['target_bundles']; + } + } foreach ($properties as $property) { $property_label = $property->getLabel(); $property = $this->getFieldsHelper()->getInnerProperty($property); if ($property instanceof EntityDataDefinitionInterface) { - $options = self::findHierarchicalProperties($property, $property_label); + $options = self::findHierarchicalProperties($property, $property_label, $bundles); if ($options) { $field_options += array($field_id => array()); $field_options[$field_id] += $options; @@ -142,20 +183,30 @@ protected function getHierarchyFields() { * The property to be searched for hierarchical nested properties. * @param string $property_label * The property's label. + * @param string[] $bundles + * (optional) Specific bundles to check for references, too. * * @return string[] * An options list of hierarchical properties, keyed by the parent * property's entity type ID and the nested properties identifier, * concatenated with a dash (-). */ - protected function findHierarchicalProperties(EntityDataDefinitionInterface $property, $property_label) { + protected function findHierarchicalProperties(EntityDataDefinitionInterface $property, $property_label, array $bundles = array()) { $entity_type_id = $property->getEntityTypeId(); $options = array(); + // Get the contained sub-properties of the property, as well as the + // properties on all the specified bundles. + $properties = $property->getPropertyDefinitions(); + foreach ($bundles as $bundle) { + $properties += $this->getEntityFieldManager() + ->getFieldDefinitions($entity_type_id, $bundle); + } + // Check properties for potential hierarchy. Check two levels down, since // Core's entity references all have an additional "entity" sub-property for // accessing the actual entity reference, which we'd otherwise miss. - foreach ($property->getPropertyDefinitions() as $name_2 => $property_2) { + foreach ($properties as $name_2 => $property_2) { $property_2_label = $property_2->getLabel(); $property_2 = $this->getFieldsHelper()->getInnerProperty($property_2); if ($property_2 instanceof EntityDataDefinitionInterface) { @@ -175,6 +226,7 @@ protected function findHierarchicalProperties(EntityDataDefinitionInterface $pro } } } + return $options; }