Chris@0: 'entity.manager']; Chris@0: Chris@0: /** Chris@17: * @var \Drupal\Core\Cache\CacheBackendInterface Chris@0: */ Chris@0: protected $cache; Chris@0: Chris@0: /** Chris@18: * The entity field manager. Chris@0: * Chris@18: * @var \Drupal\Core\Entity\EntityFieldManagerInterface Chris@0: */ Chris@18: protected $entityFieldManager; Chris@18: Chris@18: /** Chris@18: * The entity bundle info. Chris@18: * Chris@18: * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface Chris@18: */ Chris@18: protected $entityTypeBundleInfo; Chris@18: Chris@18: /** Chris@18: * The entity type manager. Chris@18: * Chris@18: * @var \Drupal\Core\Entity\EntityTypeManagerInterface Chris@18: */ Chris@18: protected $entityTypeManager; Chris@0: Chris@0: /** Chris@0: * Module handler service. Chris@0: * Chris@0: * @var \Drupal\Core\Extension\ModuleHandlerInterface Chris@0: */ Chris@0: protected $moduleHandler; Chris@0: Chris@0: /** Chris@0: * Constructor. Chris@0: * Chris@0: * @param \Drupal\Core\Cache\CacheBackendInterface $cache Chris@0: * The cache of relation URIs and their associated Typed Data IDs. Chris@18: * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager Chris@18: * The entity type manager. Chris@0: * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler Chris@0: * The module handler service. Chris@0: * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory Chris@0: * The config factory service. Chris@0: * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack Chris@0: * The request stack. Chris@18: * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info Chris@18: * The entity type bundle info. Chris@18: * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager Chris@18: * The entity field manager. Chris@0: */ Chris@18: public function __construct(CacheBackendInterface $cache, EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, RequestStack $request_stack, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, EntityFieldManagerInterface $entity_field_manager = NULL) { Chris@0: $this->cache = $cache; Chris@18: $this->entityTypeManager = $entity_type_manager; Chris@18: if (!$entity_type_bundle_info) { Chris@18: @trigger_error('The entity_type.bundle.info service must be passed to RelationLinkManager::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED); Chris@18: $entity_type_bundle_info = \Drupal::service('entity_type.bundle.info'); Chris@18: } Chris@18: $this->entityTypeBundleInfo = $entity_type_bundle_info; Chris@18: if (!$entity_field_manager) { Chris@18: @trigger_error('The entity_field.manager service must be passed to RelationLinkManager::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED); Chris@18: $entity_field_manager = \Drupal::service('entity_field.manager'); Chris@18: } Chris@18: $this->entityFieldManager = $entity_field_manager; Chris@0: $this->configFactory = $config_factory; Chris@0: $this->moduleHandler = $module_handler; Chris@0: $this->requestStack = $request_stack; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getRelationUri($entity_type, $bundle, $field_name, $context = []) { Chris@0: // Per the interface documentation of this method, the returned URI may Chris@0: // optionally also serve as the URL of a documentation page about this Chris@0: // field. However, Drupal does not currently implement such a documentation Chris@0: // page. Therefore, we return a URI assembled relative to the site's base Chris@0: // URL, which is sufficient to uniquely identify the site's entity type + Chris@0: // bundle + field for use in hypermedia formats, but we do not take into Chris@0: // account unclean URLs, language prefixing, or anything else that would be Chris@0: // required for Drupal to be able to respond with content at this URL. If a Chris@0: // module is installed that adds such content, but requires this URL to be Chris@0: // different (e.g., include a language prefix), then the module must also Chris@0: // override the RelationLinkManager class/service to return the desired URL. Chris@14: $uri = $this->getLinkDomain($context) . "/rest/relation/$entity_type/$bundle/$field_name"; Chris@0: $this->moduleHandler->alter('hal_relation_uri', $uri, $context); Chris@17: $this->moduleHandler->alterDeprecated('This hook is deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. Implement hook_hal_relation_uri_alter() instead.', 'rest_relation_uri', $uri, $context); Chris@0: return $uri; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getRelationInternalIds($relation_uri, $context = []) { Chris@0: $relations = $this->getRelations($context); Chris@0: if (isset($relations[$relation_uri])) { Chris@0: return $relations[$relation_uri]; Chris@0: } Chris@0: return FALSE; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the array of relation links. Chris@0: * Chris@0: * Any field can be handled as a relation simply by changing how it is Chris@0: * normalized. Therefore, there is no prior knowledge that can be used here Chris@0: * to determine which fields to assign relation URIs. Instead, each field, Chris@0: * even primitives, are given a relation URI. It is up to the caller to Chris@0: * determine which URIs to use. Chris@0: * Chris@0: * @param array $context Chris@0: * Context from the normalizer/serializer operation. Chris@0: * Chris@0: * @return array Chris@0: * An array of typed data IDs keyed by corresponding relation URI. The keys Chris@0: * are: Chris@0: * - 'entity_type_id' Chris@0: * - 'bundle' Chris@0: * - 'field_name' Chris@0: * - 'entity_type' (deprecated) Chris@0: * The values for 'entity_type_id', 'bundle' and 'field_name' are strings. Chris@0: * The 'entity_type' key exists for backwards compatibility and its value is Chris@0: * the full entity type object. The 'entity_type' key will be removed before Chris@0: * Drupal 9.0. Chris@0: * Chris@0: * @see https://www.drupal.org/node/2877608 Chris@0: */ Chris@0: protected function getRelations($context = []) { Chris@0: $cid = 'hal:links:relations'; Chris@0: $cache = $this->cache->get($cid); Chris@0: if (!$cache) { Chris@0: $data = $this->writeCache($context); Chris@0: } Chris@0: else { Chris@0: $data = $cache->data; Chris@0: } Chris@0: Chris@0: // @todo https://www.drupal.org/node/2716163 Remove this in Drupal 9.0. Chris@0: foreach ($data as $relation_uri => $ids) { Chris@18: $data[$relation_uri]['entity_type'] = $this->entityTypeManager->getDefinition($ids['entity_type_id']); Chris@0: } Chris@0: return $data; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Writes the cache of relation links. Chris@0: * Chris@0: * @param array $context Chris@0: * Context from the normalizer/serializer operation. Chris@0: * Chris@0: * @return array Chris@0: * An array of typed data IDs keyed by corresponding relation URI. The keys Chris@0: * are: Chris@0: * - 'entity_type_id' Chris@0: * - 'bundle' Chris@0: * - 'field_name' Chris@0: * The values for 'entity_type_id', 'bundle' and 'field_name' are strings. Chris@0: */ Chris@0: protected function writeCache($context = []) { Chris@0: $data = []; Chris@0: Chris@18: foreach ($this->entityTypeManager->getDefinitions() as $entity_type) { Chris@0: if ($entity_type instanceof ContentEntityTypeInterface) { Chris@18: foreach ($this->entityTypeBundleInfo->getBundleInfo($entity_type->id()) as $bundle => $bundle_info) { Chris@18: foreach ($this->entityFieldManager->getFieldDefinitions($entity_type->id(), $bundle) as $field_definition) { Chris@0: $relation_uri = $this->getRelationUri($entity_type->id(), $bundle, $field_definition->getName(), $context); Chris@0: $data[$relation_uri] = [ Chris@0: 'entity_type_id' => $entity_type->id(), Chris@0: 'bundle' => $bundle, Chris@0: 'field_name' => $field_definition->getName(), Chris@0: ]; Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: // These URIs only change when field info changes, so cache it permanently Chris@0: // and only clear it when the fields cache is cleared. Chris@0: $this->cache->set('hal:links:relations', $data, Cache::PERMANENT, ['entity_field_info']); Chris@0: return $data; Chris@0: } Chris@0: Chris@0: }