jsonapi_cross_bundles-8.x-1.0-alpha3/src/Context/CrossBundleFieldResolver.php
src/Context/CrossBundleFieldResolver.php
<?php
namespace Drupal\jsonapi_cross_bundles\Context;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\jsonapi\Context\FieldResolver;
use Drupal\jsonapi\ResourceType\ResourceType;
use Drupal\jsonapi_cross_bundles\ResourceType\CrossBundlesResourceType;
/**
* Decorated field resolver to support cross-bundle resource types.
*/
class CrossBundleFieldResolver extends FieldResolver {
/**
* Get all item definitions from a set of resources types by a field name.
*
* Overridden to support cross bundle resource types.
*
* @param \Drupal\jsonapi\ResourceType\ResourceType[] $resource_types
* The resource types on which the field might exist.
* @param string $field_name
* The field for which to retrieve field item definitions.
*
* @return \Drupal\Core\TypedData\ComplexDataDefinitionInterface[]
* The found field item definitions.
*/
protected function getFieldItemDefinitions(array $resource_types, $field_name) {
list($bundle_specific, $cross_bundle) = array_reduce($resource_types, function ($separated, ResourceType $resource_type) {
$separated[(int) ($resource_type instanceof CrossBundlesResourceType)][] = $resource_type;
return $separated;
}, [0 => [], 1 => []]);
$cross_bundle_candidates = array_reduce($cross_bundle, function (array $candidates, CrossBundlesResourceType $resource_type) use ($field_name) {
$per_bundle_candidates = parent::getFieldItemDefinitions($resource_type->getBundleResourceTypes(), $field_name);
// Field names are unique across bundles of an entity type and since a
// cross bundle resource type can only exist for a single resource type,
// it's acceptable to take the first candidate found—they're all the same.
return array_merge($candidates, !empty($per_bundle_candidates)
? [$resource_type->getTypeName() => array_shift($per_bundle_candidates)]
: []
);
}, []);
return array_merge(parent::getFieldItemDefinitions($bundle_specific, $field_name), $cross_bundle_candidates);
}
/**
* Gets the field access result for the 'view' operation.
*
* Overridden to support cross bundles.
*
* @param \Drupal\jsonapi\ResourceType\ResourceType $resource_type
* The JSON:API resource type on which the field exists.
* @param string $internal_field_name
* The field name for which access should be checked.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The 'view' access result.
*/
protected function getFieldAccess(ResourceType $resource_type, $internal_field_name) {
if ($resource_type instanceof CrossBundlesResourceType) {
return array_reduce($resource_type->getBundleResourceTypes(), function (AccessResult $previous, ResourceType $resource_type) use ($internal_field_name) {
return $resource_type->hasField($internal_field_name)
? $previous->andIf($this->getFieldAccess($resource_type, $internal_field_name))
: $previous;
}, AccessResult::allowed());
}
return parent::getFieldAccess($resource_type, $internal_field_name);
}
}
