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 }
|