annotate core/modules/hal/src/LinkManager/RelationLinkManager.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\hal\LinkManager;
Chris@0 4
Chris@0 5 use Drupal\Core\Cache\Cache;
Chris@0 6 use Drupal\Core\Cache\CacheBackendInterface;
Chris@0 7 use Drupal\Core\Config\ConfigFactoryInterface;
Chris@18 8 use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
Chris@0 9 use Drupal\Core\Entity\ContentEntityTypeInterface;
Chris@18 10 use Drupal\Core\Entity\EntityFieldManagerInterface;
Chris@18 11 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
Chris@18 12 use Drupal\Core\Entity\EntityTypeManagerInterface;
Chris@0 13 use Drupal\Core\Extension\ModuleHandlerInterface;
Chris@0 14 use Symfony\Component\HttpFoundation\RequestStack;
Chris@0 15
Chris@0 16 class RelationLinkManager extends LinkManagerBase implements RelationLinkManagerInterface {
Chris@18 17 use DeprecatedServicePropertyTrait;
Chris@18 18
Chris@18 19 /**
Chris@18 20 * {@inheritdoc}
Chris@18 21 */
Chris@18 22 protected $deprecatedProperties = ['entityManager' => 'entity.manager'];
Chris@0 23
Chris@0 24 /**
Chris@17 25 * @var \Drupal\Core\Cache\CacheBackendInterface
Chris@0 26 */
Chris@0 27 protected $cache;
Chris@0 28
Chris@0 29 /**
Chris@18 30 * The entity field manager.
Chris@0 31 *
Chris@18 32 * @var \Drupal\Core\Entity\EntityFieldManagerInterface
Chris@0 33 */
Chris@18 34 protected $entityFieldManager;
Chris@18 35
Chris@18 36 /**
Chris@18 37 * The entity bundle info.
Chris@18 38 *
Chris@18 39 * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
Chris@18 40 */
Chris@18 41 protected $entityTypeBundleInfo;
Chris@18 42
Chris@18 43 /**
Chris@18 44 * The entity type manager.
Chris@18 45 *
Chris@18 46 * @var \Drupal\Core\Entity\EntityTypeManagerInterface
Chris@18 47 */
Chris@18 48 protected $entityTypeManager;
Chris@0 49
Chris@0 50 /**
Chris@0 51 * Module handler service.
Chris@0 52 *
Chris@0 53 * @var \Drupal\Core\Extension\ModuleHandlerInterface
Chris@0 54 */
Chris@0 55 protected $moduleHandler;
Chris@0 56
Chris@0 57 /**
Chris@0 58 * Constructor.
Chris@0 59 *
Chris@0 60 * @param \Drupal\Core\Cache\CacheBackendInterface $cache
Chris@0 61 * The cache of relation URIs and their associated Typed Data IDs.
Chris@18 62 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
Chris@18 63 * The entity type manager.
Chris@0 64 * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
Chris@0 65 * The module handler service.
Chris@0 66 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
Chris@0 67 * The config factory service.
Chris@0 68 * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
Chris@0 69 * The request stack.
Chris@18 70 * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
Chris@18 71 * The entity type bundle info.
Chris@18 72 * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
Chris@18 73 * The entity field manager.
Chris@0 74 */
Chris@18 75 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 76 $this->cache = $cache;
Chris@18 77 $this->entityTypeManager = $entity_type_manager;
Chris@18 78 if (!$entity_type_bundle_info) {
Chris@18 79 @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 80 $entity_type_bundle_info = \Drupal::service('entity_type.bundle.info');
Chris@18 81 }
Chris@18 82 $this->entityTypeBundleInfo = $entity_type_bundle_info;
Chris@18 83 if (!$entity_field_manager) {
Chris@18 84 @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 85 $entity_field_manager = \Drupal::service('entity_field.manager');
Chris@18 86 }
Chris@18 87 $this->entityFieldManager = $entity_field_manager;
Chris@0 88 $this->configFactory = $config_factory;
Chris@0 89 $this->moduleHandler = $module_handler;
Chris@0 90 $this->requestStack = $request_stack;
Chris@0 91 }
Chris@0 92
Chris@0 93 /**
Chris@0 94 * {@inheritdoc}
Chris@0 95 */
Chris@0 96 public function getRelationUri($entity_type, $bundle, $field_name, $context = []) {
Chris@0 97 // Per the interface documentation of this method, the returned URI may
Chris@0 98 // optionally also serve as the URL of a documentation page about this
Chris@0 99 // field. However, Drupal does not currently implement such a documentation
Chris@0 100 // page. Therefore, we return a URI assembled relative to the site's base
Chris@0 101 // URL, which is sufficient to uniquely identify the site's entity type +
Chris@0 102 // bundle + field for use in hypermedia formats, but we do not take into
Chris@0 103 // account unclean URLs, language prefixing, or anything else that would be
Chris@0 104 // required for Drupal to be able to respond with content at this URL. If a
Chris@0 105 // module is installed that adds such content, but requires this URL to be
Chris@0 106 // different (e.g., include a language prefix), then the module must also
Chris@0 107 // override the RelationLinkManager class/service to return the desired URL.
Chris@14 108 $uri = $this->getLinkDomain($context) . "/rest/relation/$entity_type/$bundle/$field_name";
Chris@0 109 $this->moduleHandler->alter('hal_relation_uri', $uri, $context);
Chris@17 110 $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 111 return $uri;
Chris@0 112 }
Chris@0 113
Chris@0 114 /**
Chris@0 115 * {@inheritdoc}
Chris@0 116 */
Chris@0 117 public function getRelationInternalIds($relation_uri, $context = []) {
Chris@0 118 $relations = $this->getRelations($context);
Chris@0 119 if (isset($relations[$relation_uri])) {
Chris@0 120 return $relations[$relation_uri];
Chris@0 121 }
Chris@0 122 return FALSE;
Chris@0 123 }
Chris@0 124
Chris@0 125 /**
Chris@0 126 * Get the array of relation links.
Chris@0 127 *
Chris@0 128 * Any field can be handled as a relation simply by changing how it is
Chris@0 129 * normalized. Therefore, there is no prior knowledge that can be used here
Chris@0 130 * to determine which fields to assign relation URIs. Instead, each field,
Chris@0 131 * even primitives, are given a relation URI. It is up to the caller to
Chris@0 132 * determine which URIs to use.
Chris@0 133 *
Chris@0 134 * @param array $context
Chris@0 135 * Context from the normalizer/serializer operation.
Chris@0 136 *
Chris@0 137 * @return array
Chris@0 138 * An array of typed data IDs keyed by corresponding relation URI. The keys
Chris@0 139 * are:
Chris@0 140 * - 'entity_type_id'
Chris@0 141 * - 'bundle'
Chris@0 142 * - 'field_name'
Chris@0 143 * - 'entity_type' (deprecated)
Chris@0 144 * The values for 'entity_type_id', 'bundle' and 'field_name' are strings.
Chris@0 145 * The 'entity_type' key exists for backwards compatibility and its value is
Chris@0 146 * the full entity type object. The 'entity_type' key will be removed before
Chris@0 147 * Drupal 9.0.
Chris@0 148 *
Chris@0 149 * @see https://www.drupal.org/node/2877608
Chris@0 150 */
Chris@0 151 protected function getRelations($context = []) {
Chris@0 152 $cid = 'hal:links:relations';
Chris@0 153 $cache = $this->cache->get($cid);
Chris@0 154 if (!$cache) {
Chris@0 155 $data = $this->writeCache($context);
Chris@0 156 }
Chris@0 157 else {
Chris@0 158 $data = $cache->data;
Chris@0 159 }
Chris@0 160
Chris@0 161 // @todo https://www.drupal.org/node/2716163 Remove this in Drupal 9.0.
Chris@0 162 foreach ($data as $relation_uri => $ids) {
Chris@18 163 $data[$relation_uri]['entity_type'] = $this->entityTypeManager->getDefinition($ids['entity_type_id']);
Chris@0 164 }
Chris@0 165 return $data;
Chris@0 166 }
Chris@0 167
Chris@0 168 /**
Chris@0 169 * Writes the cache of relation links.
Chris@0 170 *
Chris@0 171 * @param array $context
Chris@0 172 * Context from the normalizer/serializer operation.
Chris@0 173 *
Chris@0 174 * @return array
Chris@0 175 * An array of typed data IDs keyed by corresponding relation URI. The keys
Chris@0 176 * are:
Chris@0 177 * - 'entity_type_id'
Chris@0 178 * - 'bundle'
Chris@0 179 * - 'field_name'
Chris@0 180 * The values for 'entity_type_id', 'bundle' and 'field_name' are strings.
Chris@0 181 */
Chris@0 182 protected function writeCache($context = []) {
Chris@0 183 $data = [];
Chris@0 184
Chris@18 185 foreach ($this->entityTypeManager->getDefinitions() as $entity_type) {
Chris@0 186 if ($entity_type instanceof ContentEntityTypeInterface) {
Chris@18 187 foreach ($this->entityTypeBundleInfo->getBundleInfo($entity_type->id()) as $bundle => $bundle_info) {
Chris@18 188 foreach ($this->entityFieldManager->getFieldDefinitions($entity_type->id(), $bundle) as $field_definition) {
Chris@0 189 $relation_uri = $this->getRelationUri($entity_type->id(), $bundle, $field_definition->getName(), $context);
Chris@0 190 $data[$relation_uri] = [
Chris@0 191 'entity_type_id' => $entity_type->id(),
Chris@0 192 'bundle' => $bundle,
Chris@0 193 'field_name' => $field_definition->getName(),
Chris@0 194 ];
Chris@0 195 }
Chris@0 196 }
Chris@0 197 }
Chris@0 198 }
Chris@0 199 // These URIs only change when field info changes, so cache it permanently
Chris@0 200 // and only clear it when the fields cache is cleared.
Chris@0 201 $this->cache->set('hal:links:relations', $data, Cache::PERMANENT, ['entity_field_info']);
Chris@0 202 return $data;
Chris@0 203 }
Chris@0 204
Chris@0 205 }