3 namespace Drupal\hal\LinkManager;
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Core\Cache\CacheBackendInterface;
7 use Drupal\Core\Config\ConfigFactoryInterface;
8 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
9 use Drupal\Core\Extension\ModuleHandlerInterface;
10 use Symfony\Component\HttpFoundation\RequestStack;
12 class TypeLinkManager extends LinkManagerBase implements TypeLinkManagerInterface {
15 * Injected cache backend.
17 * @var \Drupal\Core\Cache\CacheBackendInterface;
22 * Module handler service.
24 * @var \Drupal\Core\Extension\ModuleHandlerInterface
26 protected $moduleHandler;
29 * The bundle info service.
31 * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
33 protected $bundleInfoService;
38 * @param \Drupal\Core\Cache\CacheBackendInterface $cache
39 * The injected cache backend for caching type URIs.
40 * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
41 * The module handler service.
42 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
43 * The config factory service.
44 * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
46 * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info_service
47 * The bundle info service.
49 public function __construct(CacheBackendInterface $cache, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, RequestStack $request_stack, EntityTypeBundleInfoInterface $bundle_info_service) {
50 $this->cache = $cache;
51 $this->configFactory = $config_factory;
52 $this->moduleHandler = $module_handler;
53 $this->requestStack = $request_stack;
54 $this->bundleInfoService = $bundle_info_service;
60 public function getTypeUri($entity_type, $bundle, $context = []) {
61 // Per the interface documentation of this method, the returned URI may
62 // optionally also serve as the URL of a documentation page about this
63 // bundle. However, Drupal does not currently implement such a documentation
64 // page. Therefore, we return a URI assembled relative to the site's base
65 // URL, which is sufficient to uniquely identify the site's entity type and
66 // bundle for use in hypermedia formats, but we do not take into account
67 // unclean URLs, language prefixing, or anything else that would be required
68 // for Drupal to be able to respond with content at this URL. If a module is
69 // installed that adds such content, but requires this URL to be different
70 // (e.g., include a language prefix), then the module must also override the
71 // TypeLinkManager class/service to return the desired URL.
72 $uri = $this->getLinkDomain() . "/rest/type/$entity_type/$bundle";
73 $this->moduleHandler->alter('hal_type_uri', $uri, $context);
74 // @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This
75 // hook is invoked to maintain backwards compatibility
76 // @see https://www.drupal.org/node/2830467
77 $this->moduleHandler->alter('rest_type_uri', $uri, $context);
84 public function getTypeInternalIds($type_uri, $context = []) {
85 $types = $this->getTypes($context);
86 if (isset($types[$type_uri])) {
87 return $types[$type_uri];
93 * Get the array of type links.
95 * @param array $context
96 * Context from the normalizer/serializer operation.
99 * An array of typed data ids (entity_type and bundle) keyed by
100 * corresponding type URI.
102 protected function getTypes($context = []) {
103 $cid = 'hal:links:types';
104 $cache = $this->cache->get($cid);
106 $data = $this->writeCache($context);
109 $data = $cache->data;
115 * Writes the cache of type links.
117 * @param array $context
118 * Context from the normalizer/serializer operation.
121 * An array of typed data ids (entity_type and bundle) keyed by
122 * corresponding type URI.
124 protected function writeCache($context = []) {
127 // Type URIs correspond to bundles. Iterate through the bundles to get the
128 // URI and data for them.
129 $entity_types = \Drupal::entityManager()->getDefinitions();
130 foreach ($this->bundleInfoService->getAllBundleInfo() as $entity_type_id => $bundles) {
131 // Only content entities are supported currently.
132 // @todo Consider supporting config entities.
133 if ($entity_types[$entity_type_id]->entityClassImplements(ConfigEntityInterface::class)) {
136 foreach ($bundles as $bundle => $bundle_info) {
137 // Get a type URI for the bundle.
138 $bundle_uri = $this->getTypeUri($entity_type_id, $bundle, $context);
139 $data[$bundle_uri] = [
140 'entity_type' => $entity_type_id,
145 // These URIs only change when entity info changes, so cache it permanently
146 // and only clear it when entity_info is cleared.
147 $this->cache->set('hal:links:types', $data, Cache::PERMANENT, ['entity_types']);