jsonapi_cross_bundles-8.x-1.0-alpha3/src/ResourceType/CrossBundleResourceTypeRepository.php

src/ResourceType/CrossBundleResourceTypeRepository.php
<?php

namespace Drupal\jsonapi_cross_bundles\ResourceType;

use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\jsonapi\ResourceType\ResourceType;
use Drupal\jsonapi\ResourceType\ResourceTypeRelationship;
use Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface;
use Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException;

/**
 * Provides a decorated resource type repository for cross bundle collections.
 */
class CrossBundleResourceTypeRepository implements ResourceTypeRepositoryInterface {

  /**
   * The wrapped service.
   *
   * @var \Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface
   */
  private $inner;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The cache backend.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cache;

  /**
   * The shim.
   *
   * @var \Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface|\Drupal\jsonapi_cross_bundles\ResourceType\ResourceTypeRepositoryShim
   */
  protected $shim;

  /**
   * CrossBundleResourceTypeRepository constructor.
   *
   * @param \Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface $inner
   *   The wrapped service.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
   *   The cache backend.
   * @param \Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface|\Drupal\jsonapi_cross_bundles\ResourceType\ResourceTypeRepositoryShim $shim
   *   The shim.
   */
  public function __construct(ResourceTypeRepositoryInterface $inner, EntityTypeManagerInterface $entity_type_manager, CacheBackendInterface $cache, ResourceTypeRepositoryInterface $shim) {
    $this->inner = $inner;
    $this->entityTypeManager = $entity_type_manager;
    $this->cache = $cache;
    $this->shim = $shim;
  }

  /**
   * {@inheritdoc}
   */
  public function getByTypeName($type_name) {
    // Ensure this repository code has a cache to set the cache key.
    $this->all();
    return $this->inner->getByTypeName($type_name);
  }

  /**
   * {@inheritdoc}
   */
  public function get($entity_type_id, $bundle) {
    // Ensure this repository code has a cache to set the cache key.
    $this->all();
    return $this->inner->get($entity_type_id, $bundle);
  }

  /**
   * {@inheritdoc}
   */
  public function all() {
    $decorated_resource_types = [];
    $cached = $this->cache->get('jsonapi.resource_types', FALSE);
    if ($cached === FALSE) {
      $initial_resource_types = $this->inner->all();
      $grouped_by_entity_type_id = array_reduce($initial_resource_types, function ($grouped, ResourceType $resource_type) {
        return array_merge_recursive($grouped, [
          $resource_type->getEntityTypeId() => [$resource_type],
        ]);
      }, []);
      $cross_bundle_resource_types = [];
      $entity_types = $this->entityTypeManager->getDefinitions();
      foreach ($grouped_by_entity_type_id as $entity_type_id => $resource_types) {
        $entity_type = $entity_types[$entity_type_id];
        if (!$entity_type->getKey('bundle')) {
          continue;
        }
        // If none of the bundle-specific resource types is locatable, the
        // cross-bundle resource type should not be locatable.
        $at_least_one_is_locatable = array_reduce($resource_types, function ($at_least_one_is_locatable, ResourceType $resource_type) {
          return $at_least_one_is_locatable ?: $resource_type->isLocatable();
        }, FALSE);
        $field_mapping_superset = static::getFieldMappingSuperset(array_map(function (ResourceType $resource_type) use ($entity_type) {
          return $this->shim->getFields(
            $this->shim->getAllFieldNames($entity_type, $resource_type->getBundle()),
            $entity_type,
            $resource_type->getBundle()
          );
        }, $resource_types));
        $cross_bundle_resource_type = new CrossBundlesResourceType(
          $entity_type_id,
          $entity_type_id,
          $entity_type->getClass(),
          $entity_type->isInternal(),
          $at_least_one_is_locatable,
          FALSE,
          FALSE,
          $field_mapping_superset
        );
        $cross_bundle_resource_type->setBundleResourceTypes($resource_types);

        $cross_bundle_resource_type->setRelatableResourceTypes($this->getRelatableResourceTypesSuperset($resource_types, $field_mapping_superset, $initial_resource_types));
        $cross_bundle_resource_types[$cross_bundle_resource_type->getTypeName()] = $cross_bundle_resource_type;
      }
      $decorated_resource_types = array_merge($initial_resource_types, $cross_bundle_resource_types);
      $this->cache->set('jsonapi.resource_types', $decorated_resource_types, Cache::PERMANENT, ['jsonapi_resource_types']);
    }
    return $cached ? $cached->data : $decorated_resource_types;
  }

  /**
   * Computes a superset of field mappings.
   *
   * @param \Drupal\jsonapi\ResourceType\ResourceTypeField[] $field_mappings
   *   An array of field mappings for each of the bundle-specific
   *   resource types that a cross-bundle resource type will aggregate.
   *
   * @return array
   *   The field mapping superset.
   *
   * @see \Drupal\jsonapi\ResourceType\ResourceTypeRepository::getFieldMapping()
   */
  public static function getFieldMappingSuperset(array $field_mappings) {
    /** @var \Drupal\jsonapi\ResourceType\ResourceTypeField[] $superset */
    $superset = [];
    foreach ($field_mappings as $field_mapping) {
      // Merge the different field mappings into a single superset of all
      // possible field mappings for a single entity type.
      $undefined_field_names = [];
      /** @var \Drupal\jsonapi\ResourceType\ResourceTypeField[] $superset */
      $superset = array_reduce(array_keys($field_mapping), function ($superset, $internal_field_name) use ($field_mapping, &$undefined_field_names) {
        if (in_array($internal_field_name, $undefined_field_names, TRUE)) {
          return $superset;
        }
        // Check whether the field name already has a mapping.
        if (isset($superset[$internal_field_name])) {
          // Check to see if the field name is mapped or not. A boolean means
          // the field is not mapped and is either enabled or disabled.
          if (is_bool($superset[$internal_field_name])) {
            // The previous mapping is just enabled/disabled. If the new mapping
            // is a string, use it. If the it is enabled, use it. If it is
            // disabled, use the previous field mapping in case it is enabled.
            $superset[$internal_field_name] = $field_mapping[$internal_field_name] ?: $superset[$internal_field_name];
          }
          // @note we cannot do strict checking since these are objects.
          elseif ($superset[$internal_field_name] != $field_mapping[$internal_field_name]) {
            // There are must be more than one possible field mapping, so leave
            // that behavior undefined.
            $undefined_field_names[] = $internal_field_name;
            unset($superset[$internal_field_name]);
          }
        }
        else {
          // This is a previous unseen mapping, so use the new mapping.
          $resource_type_field = $field_mapping[$internal_field_name];
          $superset[$internal_field_name] = $resource_type_field;
        }
        return $superset;
      }, $superset);
    }
    return $superset;
  }

  /**
   * Computes the superset of relatable resource types.
   *
   * @param array $resource_types
   *   An array of resource types to be aggregated.
   * @param array $field_mapping
   *   The cross-bundle resource type field mapping.
   * @param array $initial_resource_types
   *   The initial resource types.
   *
   * @return array
   *   A superset of relatable resource types, keyed by public field name.
   *
   * @see \Drupal\jsonapi\ResourceType\ResourceTypeRepository::getRelatableResourceTypesFromFieldDefinition()
   */
  public function getRelatableResourceTypesSuperset(array $resource_types, array $field_mapping, array $initial_resource_types) {
    $relatable_resource_types = [];
    foreach ($resource_types as $resource_type) {
      $relatable_resource_types[] = $this->shim->calculateRelatableResourceTypes($resource_type, $initial_resource_types);
    }
    $relatable_resource_types = array_merge([], ...$relatable_resource_types);

    $mapped_resource_types = array_filter(array_map(function ($item) {
      return $item instanceof ResourceTypeRelationship ? $item->getPublicName() : NULL;
    }, $field_mapping));
    return array_intersect_key($relatable_resource_types, array_flip($mapped_resource_types));
  }

}

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

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