butils-8.x-1.x-dev/src/FieldTrait.php

src/FieldTrait.php
<?php

namespace Drupal\butils;

use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\EntityInterface;

/**
 * Field trait.
 *
 * Field related utils.
 */
trait FieldTrait {

  /**
   * Get all field extended definitions for an entity of a type.
   *
   * @param string $entity_type
   *   Entity type.
   * @param string $bundle
   *   Entity bundle.
   *
   * @return array
   *   List of field definitions.
   */
  public function getFieldDefinitions($entity_type, $bundle) {
    $list = $this->entityFieldManager->getFieldDefinitions($entity_type, $bundle);
    $extended_definitions = [];
    foreach ($list as $name => $definition) {
      $extended_definitions[$name] = [
        'field_name' => $name,
        'entity_type' => $entity_type,
        'bundle' => $bundle,
        'definition' => $definition,
      ];
      $extended_definitions[$name]['details'] = $this->getFieldDefinitionsDetails($extended_definitions[$name]);
    }

    return $extended_definitions;
  }

  /**
   * Gets the details of a filter.
   *
   * @param array $extended_definition
   *   Field's extended definition object.
   *
   * @return array
   *   Filter details usable for filtering.
   */
  protected function getFieldDefinitionsDetails(array $extended_definition) {
    $definition = $extended_definition['definition'];
    $form_display = $this->entityTypeManager->getStorage('entity_form_display')->load($extended_definition['entity_type'] . '.' . $extended_definition['bundle'] . '.default');
    if (empty($form_display)) {
      return [];
    }
    $component = $form_display->getComponent($extended_definition['field_name']);
    $field_type = $definition->getType();

    // Get widget type.
    if (!empty($component['type'])) {
      $widget_type = $component['type'];
    }

    // Base fields have no component data. Guess from field type.
    else {
      $widget_type = 'boolean_checkbox';
      if ($field_type === 'entity_reference') {
        $widget_type = 'entity_reference_autocomplete';
      }
    }

    // Add new details to existing, flatten the render objects.
    $details = [
      'label' => $definition->getLabel(),
      'description' => $definition->getDescription(),
      'field_type' => $field_type,
      'widget' => $widget_type,
    ];
    $details += $extended_definition;
    if (is_object($details['description'])) {
      $details['description'] = (string) $details['description'];
    }
    if (is_object($details['label'])) {
      $details['description'] = (string) $details['label'];
    }

    // Additions for entity reference.
    if ($field_type === 'entity_reference') {
      $details['ref_target_type'] = $definition->getSetting('target_type');
      $handler_settings = $definition->getSetting('handler_settings');
      if (!empty($handler_settings['target_bundles'])) {
        $details['ref_target_bundle'] = reset($handler_settings['target_bundles']);
      }
      else {
        $details['ref_target_bundle'] = '';
      }
    }

    return $details;
  }

  /**
   * Checks if entity type and bundle has a field with name.
   *
   * @param string $field_name
   *   Field name.
   * @param string $entity_type
   *   Entity type.
   * @param string $bundle
   *   Bundle of an entity.
   *
   * @return bool
   *   True if field with the specified name exists.
   */
  public function bundleHasField($field_name, $entity_type, $bundle = NULL) {
    $bundle = $bundle ?: $entity_type;
    $list = $this->entityFieldManager->getFieldDefinitions($entity_type, $bundle);

    return !empty($list[$field_name]);
  }

  /**
   * Empty an entity's field.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   Entity posessing the field.
   * @param string $field_name
   *   Field name.
   * @param bool $save
   *   Whether or not the entity should be saved at the end.
   */
  public function emptyField(EntityInterface $entity, $field_name, $save = TRUE) {
    if (!$entity instanceof FieldableEntityInterface || !$entity->hasField($field_name)) {
      return;
    }
    $items = $entity->get($field_name);
    $has_items = !!$items->count();
    for ($i = 0; $i < $items->count(); $i++) {
      $items->removeItem($i);

      // Adjust for a rekey().
      $i--;
    }
    if ($has_items && $save) {
      $entity->save();
    }
  }

  /**
   * View field value without the wrappers and label.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   Entity posessing the field.
   * @param string $field_name
   *   Field name.
   * @param array $options
   *   Render options.
   *     - display: Render display mode. Default "default".
   *     - multiple: Whether to render multivalue items. Default TRUE.
   *
   * @return array
   *   Build array.
   */
  public function viewField(EntityInterface $entity, $field_name, array $options = []) {
    $options['display'] = $options['display'] ?? 'default';
    $options['multiple'] = $options['multiple'] ?? TRUE;
    if (!$entity instanceof FieldableEntityInterface
      || !$entity->hasField($field_name)) {
      return [];
    }

    // Build.
    $field_item = $entity->{$field_name};
    $field_build = [];
    if (!empty($field_item)) {
      $definition = $field_item->getFieldDefinition();
      $field_build = $field_item->view($options['display']);
      $field_build['#field_type'] = $definition->get('field_type');
      $field_build['#label_display'] = 'hidden';
    }

    // Reduce.
    if (empty($options['multiple'])) {
      $count = $field_item->count();
      if ($count > 1) {
        for ($x = 1; $x <= $count; $x++) {
          unset($field_build[$x]);
        }
      }
    }

    return $field_build;
  }

  /**
   * Renders field value without the wrappers and label.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   Entity posessing the field.
   * @param string $field_name
   *   Field name.
   * @param array $options
   *   Render options.
   *     - display: Render display mode. Default "default".
   *     - multiple: Whether to render multivalue items. Default TRUE.
   *     - full_html: Whether to render full html. Default FALSE.
   *
   * @return string
   *   Field value.
   */
  public function renderField(EntityInterface $entity, $field_name, array $options = []) {
    $field_build = $this->viewField($entity, $field_name, $options);

    switch ($field_build['#field_type']) {
      case 'file':
      case 'image':
      case 'entity_reference':
        $result = (string) $this->renderer->renderRoot($field_build);
        break;

      default:
        $result = (string) $this->renderer->renderRoot($field_build);
        if (empty($options['full_html'])) {
          $result = strip_tags($result);
        }
    }
    $result = $this->cleanHtml($result);

    return $result;
  }

  /**
   * A hack to get field value without a Node::load().
   *
   * To be used for speed critical cases, use Node::load() otherwise.
   *
   * @param int|array $entity_id
   *   Entity id/ids.
   * @param string $field_name
   *   Name of the field.
   * @param string $entity_type
   *   Entity type machine string, like "node".
   * @param int $delta
   *   Field value Delta.
   *
   * @return mixed
   *   Query result.
   */
  public function getFieldValueByIds($entity_id, $field_name, $entity_type = 'node', $delta = 0) {
    $entity_storage = $this->entityTypeManager->getStorage($entity_type);
    $field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type);
    $definition = $field_storage_definitions[$field_name];
    $is_base = $definition->isBaseField();
    $table_mapping = $entity_storage->getTableMapping($field_storage_definitions);
    $table = $table_mapping->getFieldTableName($field_name);
    $table_columns = $table_mapping->getAllColumns($table);
    $entity_id = (array) $entity_id;
    $query = $this->database->select($table, 't');
    if (in_array('delta', $table_columns)) {
      $query->condition('delta', $delta);
    }
    if ($is_base) {
      $keys = $this->entityTypeManager->getDefinition($entity_type)->getKeys();
      $query->fields('t', [$field_name]);
      $query->condition($keys['id'], $entity_id, 'IN');
    }
    else {
      $columns = array_keys($definition->getSchema()['columns']);
      $value_key = reset($columns);
      $field_mapping = $table_mapping->getFieldColumnName($definition, $value_key);
      $query->fields('t', [$field_mapping]);
      $query->condition('entity_id', $entity_id, 'IN');
    }

    return $query->execute()->fetchField();
  }

  /**
   * A hack to empty a field value without a Node::save().
   *
   * To be used for speed critical cases, use Node::save() otherwise.
   * Will not handle cache invalidation.
   *
   * @param int|array $entity_id
   *   Entity id/ids.
   * @param string $field_name
   *   Name of the field.
   * @param string $entity_type
   *   Entity type machine string, like "node".
   *
   * @return int
   *   Number of deleted rows.
   */
  public function emptyFieldDb($entity_id, $field_name, $entity_type = 'node') {
    $entity_storage = $this->entityTypeManager->getStorage($entity_type);
    $field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type);
    $definition = $field_storage_definitions[$field_name];
    $is_base = $definition->isBaseField();
    $table_mapping = $entity_storage->getTableMapping($field_storage_definitions);
    $table = $table_mapping->getFieldTableName($field_name);
    $table_columns = $table_mapping->getAllColumns($table);
    $entity_id = (array) $entity_id;

    // Do not delete base field values.
    if ($is_base) {
      throw new \Exception('Will not delete the values of the base fields directly.');
    }

    // Do not delete from incompatible fields.
    if (!in_array('entity_id', $table_columns)) {
      throw new \Exception('The specified field type can not be emptied directly.');
    }

    return $this->database->delete($table)
      ->condition('entity_id', $entity_id, 'IN')
      ->execute();
  }

  /**
   * Removes reference to an entity from the reference field.
   *
   * @param \Drupal\Core\Entity\EntityInterface $parent
   *   Parent entity.
   * @param string $field_name
   *   Reference entity field.
   * @param string $target_id
   *   Referenced entity id.
   *
   * @return int
   *   Returns amount of remaining referenced items.
   */
  public function fieldRemoveRerence(EntityInterface $parent, $field_name, $target_id) {
    $pids = array_column($parent->{$field_name}->getValue(), 'target_id', 'target_id');
    unset($pids[$parent->id()]);
    $parent->{$field_name} = $pids;
    $parent->save();

    return count($pids);
  }

  /**
   * Removes reference to an entity from the reference revisions field.
   *
   * @param \Drupal\Core\Entity\EntityInterface $parent
   *   Parent entity.
   * @param string $field_name
   *   Reference entity field.
   * @param string $target_id
   *   Referenced entity id.
   *
   * @return int
   *   Returns amount of remaining referenced items.
   */
  public function fieldRemoveReferenceRevision(EntityInterface $parent, $field_name, $target_id) {
    $values = $parent->{$field_name}->getValue();
    $has_change = FALSE;
    foreach ($values as $key => $value) {
      if ((string) $value['target_id'] === (string) $target_id) {
        unset($values[$key]);
        $has_change = TRUE;
      }
    }
    if ($has_change) {
      $parent->{$field_name} = $values;
      $parent->save();
    }

    return count($values);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc