コード例 #1
0
ファイル: Index.php プロジェクト: jkyto/agolf
  /**
   * Converts an array of property definitions into Search API field objects.
   *
   * Stores the resulting values in $this->fields, to be returned by subsequent
   * getFields() calls.
   *
   * @param \Drupal\Core\TypedData\DataDefinitionInterface[] $properties
   *   An array of properties on some complex data object.
   * @param string|null $datasource_id
   *   (optional) The ID of the datasource to which these properties belong.
   * @param string $prefix
   *   Internal use only. A prefix to use for the generated field names in this
   *   method.
   * @param string $label_prefix
   *   Internal use only. A prefix to use for the generated field labels in this
   *   method.
   *
   * @throws \Drupal\search_api\SearchApiException
   *   Thrown if $datasource_id is not valid datasource for this index.
   */
  protected function convertPropertyDefinitionsToFields(array $properties, $datasource_id = NULL, $prefix = '', $label_prefix = '') {
    $type_mapping = Utility::getFieldTypeMapping();
    $field_options = isset($this->options['fields']) ? $this->options['fields'] : array();
    $enabled_additional_fields = isset($this->options['additional fields']) ? $this->options['additional fields'] : array();

    // All field identifiers should start with the datasource ID.
    if (!$prefix && $datasource_id) {
      $prefix = $datasource_id . self::DATASOURCE_ID_SEPARATOR;
    }
    $datasource_label = $datasource_id ? $this->getDatasource($datasource_id)->label() . ' » ' : '';

    // Loop over all properties and handle them accordingly.
    $recurse = array();
    foreach ($properties as $property_path => $property) {
      $original_property = $property;
      if ($property instanceof PropertyInterface) {
        $property = $property->getWrappedProperty();
      }
      $key = "$prefix$property_path";
      $label = $label_prefix . $property->getLabel();
      $description = $property->getDescription();
      while ($property instanceof ListDataDefinitionInterface) {
        $property = $property->getItemDefinition();
      }
      while ($property instanceof DataReferenceDefinitionInterface) {
        $property = $property->getTargetDefinition();
      }
      if ($property instanceof ComplexDataDefinitionInterface) {
        $main_property = $property->getMainPropertyName();
        $nested_properties = $property->getPropertyDefinitions();

        // Don't add the additional 'entity' property for entity reference
        // fields which don't target a content entity type.
        $referenced_entity_type_label = NULL;
        if ($property instanceof FieldItemDataDefinition && in_array($property->getDataType(), array('field_item:entity_reference', 'field_item:image', 'field_item:file'))) {
          $entity_type = $this->entityManager()->getDefinition($property->getSetting('target_type'));
          if (!$entity_type->isSubclassOf('Drupal\Core\Entity\ContentEntityInterface')) {
            unset($nested_properties['entity']);
          }
          else {
            $referenced_entity_type_label = $entity_type->getLabel();
          }
        }

        $additional = count($nested_properties) > 1;
        if (!empty($enabled_additional_fields[$key]) && $nested_properties) {
          // We allow the main property to be indexed directly, so we don't
          // have to add it again for the nested fields.
          if ($main_property) {
            unset($nested_properties[$main_property]);
          }
          if ($nested_properties) {
            $additional = TRUE;
            $recurse[] = array($nested_properties, $datasource_id, "$key:", "$label » ");
          }
        }

        if ($additional) {
          $additional_field = Utility::createAdditionalField($this, $key);
          $additional_field->setLabel("$label [$key]");
          $additional_field->setDescription($description);
          $additional_field->setEnabled(!empty($enabled_additional_fields[$key]));
          $additional_field->setLocked(FALSE);
          if ($original_property instanceof PropertyInterface) {
            $additional_field->setHidden($original_property->isHidden());
          }
          $this->fields[0]['additional fields'][$key] = $additional_field;
          if ($additional_field->isEnabled()) {
            while ($pos = strrpos($property_path, ':')) {
              $property_path = substr($property_path, 0, $pos);
              /** @var \Drupal\search_api\Item\AdditionalFieldInterface $additional_field */
              $additional_field = $this->fields[0]['additional fields'][$property_path];
              $additional_field->setEnabled(TRUE);
              $additional_field->setLocked();
            }
          }
        }
        // If the complex data type has a main property, we can index that
        // directly here. Otherwise, we don't add it and continue with the next
        // property.
        if (!$main_property) {
          continue;
        }
        $parent_type = $property->getDataType();
        $property = $property->getPropertyDefinition($main_property);
        if (!$property) {
          continue;
        }

        // If there are additional properties, add the label for the main
        // property to make it clear what it refers to.
        if ($additional) {
          $nested_label = $property->getLabel();
          if ($referenced_entity_type_label) {
            $nested_label = str_replace('@label', $referenced_entity_type_label, $nested_label);
          }

          $label .= ' » ' . $nested_label;
        }
      }

      $type = $property->getDataType();
      // Try to see if there's a mapping for a parent.child data type.
      if (isset($parent_type) && isset($type_mapping[$parent_type . '.' . $type])) {
        $field_type = $type_mapping[$parent_type . '.' . $type];
      }
      elseif (!empty($type_mapping[$type])) {
        $field_type = $type_mapping[$type];
      }
      else {
        // Failed to map this type, skip.
        if (!isset($type_mapping[$type])) {
          $this->unmappedFields[$type][$key] = $key;
        }
        continue;
      }

      $field = Utility::createField($this, $key);
      $field->setType($field_type);
      $field->setLabel($label);
      $field->setLabelPrefix($datasource_label);
      $field->setDescription($description);
      $field->setIndexed(FALSE);
      // To make it possible to lock fields that are, technically, nested, use
      // the original $property for this check.
      if ($original_property instanceof PropertyInterface) {
        $field->setIndexedLocked($original_property->isIndexedLocked());
        $field->setTypeLocked($original_property->isTypeLocked());
        $field->setHidden($original_property->isHidden());
      }
      $this->fields[0]['fields'][$key] = $field;
      if (isset($field_options[$key]) || $field->isIndexedLocked()) {
        $field->setIndexed(TRUE);
        if (isset($field_options[$key])) {
          $field->setType($field_options[$key]['type']);
          if (isset($field_options[$key]['boost'])) {
            $field->setBoost($field_options[$key]['boost']);
          }
        }
        $this->fields[1]['fields'][$key] = $field;
      }
    }
    foreach ($recurse as $arguments) {
      call_user_func_array(array($this, 'convertPropertyDefinitionsToFields'), $arguments);
    }

    // Order unindexed fields alphabetically.
    $sort_by_label = function(GenericFieldInterface $field1, GenericFieldInterface $field2) {
      return strnatcasecmp($field1->getLabel(), $field2->getLabel());
    };
    uasort($this->fields[0]['fields'], $sort_by_label);
    uasort($this->fields[0]['additional fields'], $sort_by_label);
  }