Commit 20add381 authored by alexpott's avatar alexpott

Issue #2336247 by larowlan, andythorne: Make Relation and Type domain configurable based on context

parent 74db0531
......@@ -76,7 +76,7 @@ public function normalize($entity, $format = NULL, array $context = array()) {
'href' => $this->getEntityUri($entity),
),
'type' => array(
'href' => $this->linkManager->getTypeUri($entity->getEntityTypeId(), $entity->bundle()),
'href' => $this->linkManager->getTypeUri($entity->getEntityTypeId(), $entity->bundle(), $context),
),
),
);
......@@ -132,7 +132,7 @@ public function denormalize($data, $class, $format = NULL, array $context = arra
}
// Create the entity.
$typed_data_ids = $this->getTypedDataIds($data['_links']['type']);
$typed_data_ids = $this->getTypedDataIds($data['_links']['type'], $context);
$entity_type = $this->entityManager->getDefinition($typed_data_ids['entity_type']);
$langcode_key = $entity_type->getKey('langcode');
$values = array();
......@@ -210,13 +210,14 @@ protected function getEntityUri($entity) {
*
* @param array $types
* The type array(s) (value of the 'type' attribute of the incoming data).
* @param array $context
* Context from the normalizer/serializer operation.
*
* @return array
* The typed data IDs.
*
* @throws \Symfony\Component\Serializer\Exception\UnexpectedValueException
*/
protected function getTypedDataIds($types) {
protected function getTypedDataIds($types, $context = array()) {
// The 'type' can potentially contain an array of type objects. By default,
// Drupal only uses a single type in serializing, but allows for multiple
// types when deserializing.
......@@ -231,7 +232,7 @@ protected function getTypedDataIds($types) {
$type_uri = $type['href'];
// Check whether the URI corresponds to a known type on this site. Break
// once one does.
if ($typed_data_ids = $this->linkManager->getTypeInternalIds($type['href'])) {
if ($typed_data_ids = $this->linkManager->getTypeInternalIds($type['href'], $context)) {
break;
}
}
......
......@@ -85,7 +85,7 @@ public function normalize($field_item, $format = NULL, array $context = array())
// objects.
$field_name = $field_item->getParent()->getName();
$entity = $field_item->getEntity();
$field_uri = $this->linkManager->getRelationUri($entity->getEntityTypeId(), $entity->bundle(), $field_name);
$field_uri = $this->linkManager->getRelationUri($entity->getEntityTypeId(), $entity->bundle(), $field_name, $context);
return array(
'_links' => array(
$field_uri => array($link),
......
......@@ -39,8 +39,7 @@ protected function setUp() {
$this->installEntitySchema('file');
$entity_manager = \Drupal::entityManager();
$url_assembler = \Drupal::service('unrouted_url_assembler');
$link_manager = new LinkManager(new TypeLinkManager(new MemoryBackend('default'), $url_assembler), new RelationLinkManager(new MemoryBackend('default'), $entity_manager, $url_assembler));
$link_manager = new LinkManager(new TypeLinkManager(new MemoryBackend('default'), \Drupal::moduleHandler(), \Drupal::service('config.factory'), \Drupal::service('request_stack')), new RelationLinkManager(new MemoryBackend('default'), $entity_manager, \Drupal::moduleHandler(), \Drupal::service('config.factory'), \Drupal::service('request_stack')));
// Set up the mock serializer.
$normalizers = array(
......
......@@ -83,6 +83,7 @@ protected function setUp() {
$class = get_parent_class($class);
}
$this->installConfig(array('field', 'language'));
\Drupal::service('router.builder')->rebuild();
// Add German as a language.
ConfigurableLanguage::create(array(
......@@ -134,8 +135,7 @@ protected function setUp() {
))->save();
$entity_manager = \Drupal::entityManager();
$url_assembler = \Drupal::service('unrouted_url_assembler');
$link_manager = new LinkManager(new TypeLinkManager(new MemoryBackend('default'), $url_assembler), new RelationLinkManager(new MemoryBackend('default'), $entity_manager, $url_assembler));
$link_manager = new LinkManager(new TypeLinkManager(new MemoryBackend('default'), \Drupal::moduleHandler(), \Drupal::service('config.factory'), \Drupal::service('request_stack')), new RelationLinkManager(new MemoryBackend('default'), $entity_manager, \Drupal::moduleHandler(), \Drupal::service('config.factory'), \Drupal::service('request_stack')));
$chain_resolver = new ChainEntityResolver(array(new UuidResolver($entity_manager), new TargetIdResolver()));
......
......@@ -44,3 +44,7 @@ resources:
#
# The full documentation is located at
# https://drupal.org/documentation/modules/rest
# Set the domain for REST type and relation links.
# If left blank, the site's domain will be used
link_domain: ~
......@@ -10,6 +10,9 @@ rest.settings:
sequence:
type: rest_resource
label: 'Resource'
link_domain:
type: string
label: 'Domain of the relation'
rest_resource:
type: mapping
......
......@@ -28,6 +28,53 @@ function hook_rest_resource_alter(&$definitions) {
unset($definitions['entity:view']);
}
/**
* Alter the REST type URI.
*
* Modules may wish to alter the type URI generated for a resource based on the
* context of the serializer/normalizer operation.
*
* @param string $uri
* The URI to alter.
* @param array $context
* The context from the serializer/normalizer operation.
*
* @see \Symfony\Component\Serializer\SerializerInterface::serialize()
* @see \Symfony\Component\Serializer\SerializerInterface::deserialize()
* @see \Symfony\Component\Serializer\NormalizerInterface::normalize()
* @see \Symfony\Component\Serializer\DenormalizerInterface::denormalize()
*/
function hook_rest_type_uri_alter(&$uri, $context = array()) {
if ($context['mymodule'] == TRUE) {
$base = \Drupal::config('rest.settings')->get('link_domain');
$uri = str_replace($base, 'http://mymodule.domain', $uri);
}
}
/**
* Alter the REST relation URI.
*
* Modules may wish to alter the relation URI generated for a resource based on
* the context of the serializer/normalizer operation.
*
* @param string $uri
* The URI to alter.
* @param array $context
* The context from the serializer/normalizer operation.
*
* @see \Symfony\Component\Serializer\SerializerInterface::serialize()
* @see \Symfony\Component\Serializer\SerializerInterface::deserialize()
* @see \Symfony\Component\Serializer\NormalizerInterface::normalize()
* @see \Symfony\Component\Serializer\DenormalizerInterface::denormalize()
*/
function hook_rest_relation_uri_alter(&$uri, $context = array()) {
if ($context['mymodule'] == TRUE) {
$base = \Drupal::config('rest.settings')->get('link_domain');
$uri = str_replace($base, 'http://mymodule.domain', $uri);
}
}
/**
* @} End of "addtogroup hooks".
*/
......@@ -19,10 +19,10 @@ services:
arguments: ['@rest.link_manager.type', '@rest.link_manager.relation']
rest.link_manager.type:
class: Drupal\rest\LinkManager\TypeLinkManager
arguments: ['@cache.default', '@unrouted_url_assembler']
arguments: ['@cache.default', '@module_handler', '@config.factory', '@request_stack']
rest.link_manager.relation:
class: Drupal\rest\LinkManager\RelationLinkManager
arguments: ['@cache.default', '@entity.manager', '@unrouted_url_assembler']
arguments: ['@cache.default', '@entity.manager', '@module_handler', '@config.factory', '@request_stack']
rest.resource_routes:
class: Drupal\rest\Routing\ResourceRoutes
arguments: ['@plugin.manager.rest', '@config.factory', '@logger.channel.rest']
......
<?php
/**
* @file
* Contains \Drupal\rest\LinkManager\ConfigurableLinkManagerInterface.
*/
namespace Drupal\rest\LinkManager;
/**
* Defines an interface for a link manager with a configurable domain.
*/
interface ConfigurableLinkManagerInterface {
/**
* Sets the link domain used in constructing link URIs.
*
* @param string $domain
* The link domain to use for constructing link URIs.
*
* @return $this
*/
public function setLinkDomain($domain);
}
......@@ -38,22 +38,22 @@ public function __construct(TypeLinkManagerInterface $type_link_manager, Relatio
/**
* Implements \Drupal\rest\LinkManager\TypeLinkManagerInterface::getTypeUri().
*/
public function getTypeUri($entity_type, $bundle) {
return $this->typeLinkManager->getTypeUri($entity_type, $bundle);
public function getTypeUri($entity_type, $bundle, $context = array()) {
return $this->typeLinkManager->getTypeUri($entity_type, $bundle, $context);
}
/**
* Implements \Drupal\rest\LinkManager\TypeLinkManagerInterface::getTypeInternalIds().
*/
public function getTypeInternalIds($type_uri) {
return $this->typeLinkManager->getTypeInternalIds($type_uri);
public function getTypeInternalIds($type_uri, $context = array()) {
return $this->typeLinkManager->getTypeInternalIds($type_uri, $context);
}
/**
* Implements \Drupal\rest\LinkManager\RelationLinkManagerInterface::getRelationUri().
*/
public function getRelationUri($entity_type, $bundle, $field_name) {
return $this->relationLinkManager->getRelationUri($entity_type, $bundle, $field_name);
public function getRelationUri($entity_type, $bundle, $field_name, $context = array()) {
return $this->relationLinkManager->getRelationUri($entity_type, $bundle, $field_name, $context);
}
/**
......@@ -63,4 +63,13 @@ public function getRelationInternalIds($relation_uri) {
return $this->relationLinkManager->getRelationInternalIds($relation_uri);
}
/**
* {@inheritdoc}
*/
public function setLinkDomain($domain) {
$this->relationLinkManager->setLinkDomain($domain);
$this->typeLinkManager->setLinkDomain($domain);
return $this;
}
}
<?php
/**
* @file
* Contains \Drupal\rest\LinkManager\LinkManagerBase.
*/
namespace Drupal\rest\LinkManager;
use Drupal\Core\Url;
/**
* Defines an abstract base-class for REST link manager objects.
*/
abstract class LinkManagerBase {
/**
* Link domain used for type links URIs.
*
* @var string
*/
protected $linkDomain;
/**
* Config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* {@inheritdoc}
*/
public function setLinkDomain($domain) {
$this->linkDomain = rtrim($domain, '/');
return $this;
}
/**
* Gets the link domain.
*
* @return string
* The link domain.
*/
protected function getLinkDomain() {
if (empty($this->linkDomain)) {
if ($domain = $this->configFactory->get('rest.settings')->get('link_domain')) {
$this->linkDomain = rtrim($domain, '/');
}
else {
$request = $this->requestStack->getCurrentRequest();
$this->linkDomain = $request->getSchemeAndHttpHost() . $request->getBasePath();
}
}
return $this->linkDomain;
}
}
......@@ -9,11 +9,13 @@
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class RelationLinkManager implements RelationLinkManagerInterface {
class RelationLinkManager extends LinkManagerBase implements RelationLinkManagerInterface {
/**
* @var \Drupal\Core\Cache\CacheBackendInterface;
......@@ -28,11 +30,11 @@ class RelationLinkManager implements RelationLinkManagerInterface {
protected $entityManager;
/**
* The unrouted URL assembler.
* Module handler service.
*
* @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $urlAssembler;
protected $moduleHandler;
/**
* Constructor.
......@@ -41,27 +43,35 @@ class RelationLinkManager implements RelationLinkManagerInterface {
* The cache of relation URIs and their associated Typed Data IDs.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Utility\UnroutedUrlAssemblerInterface $url_assembler
* The unrouted URL assembler.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory service.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
*/
public function __construct(CacheBackendInterface $cache, EntityManagerInterface $entity_manager, UnroutedUrlAssemblerInterface $url_assembler) {
public function __construct(CacheBackendInterface $cache, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, RequestStack $request_stack) {
$this->cache = $cache;
$this->entityManager = $entity_manager;
$this->urlAssembler = $url_assembler;
$this->configFactory = $config_factory;
$this->moduleHandler = $module_handler;
$this->requestStack = $request_stack;
}
/**
* {@inheritdoc}
*/
public function getRelationUri($entity_type, $bundle, $field_name) {
return $this->urlAssembler->assemble("base:rest/relation/$entity_type/$bundle/$field_name", array('absolute' => TRUE));
public function getRelationUri($entity_type, $bundle, $field_name, $context = array()) {
$uri = $this->getLinkDomain() . "/rest/relation/$entity_type/$bundle/$field_name";
$this->moduleHandler->alter('rest_relation_uri', $uri, $context);
return $uri;
}
/**
* {@inheritdoc}
*/
public function getRelationInternalIds($relation_uri) {
$relations = $this->getRelations();
public function getRelationInternalIds($relation_uri, $context = array()) {
$relations = $this->getRelations($context);
if (isset($relations[$relation_uri])) {
return $relations[$relation_uri];
}
......@@ -77,15 +87,18 @@ public function getRelationInternalIds($relation_uri) {
* even primitives, are given a relation URI. It is up to the caller to
* determine which URIs to use.
*
* @param array $context
* Context from the normalizer/serializer operation.
*
* @return array
* An array of typed data ids (entity_type, bundle, and field name) keyed
* by corresponding relation URI.
*/
protected function getRelations() {
protected function getRelations($context = array()) {
$cid = 'rest:links:relations';
$cache = $this->cache->get($cid);
if (!$cache) {
$this->writeCache();
$this->writeCache($context);
$cache = $this->cache->get($cid);
}
return $cache->data;
......@@ -93,15 +106,18 @@ protected function getRelations() {
/**
* Writes the cache of relation links.
*
* @param array $context
* Context from the normalizer/serializer operation.
*/
protected function writeCache() {
protected function writeCache($context = array()) {
$data = array();
foreach ($this->entityManager->getDefinitions() as $entity_type) {
if ($entity_type instanceof ContentEntityTypeInterface) {
foreach ($this->entityManager->getBundleInfo($entity_type->id()) as $bundle => $bundle_info) {
foreach ($this->entityManager->getFieldDefinitions($entity_type->id(), $bundle) as $field_definition) {
$relation_uri = $this->getRelationUri($entity_type->id(), $bundle, $field_definition->getName());
$relation_uri = $this->getRelationUri($entity_type->id(), $bundle, $field_definition->getName(), $context);
$data[$relation_uri] = array(
'entity_type' => $entity_type,
'bundle' => $bundle,
......
......@@ -7,7 +7,7 @@
namespace Drupal\rest\LinkManager;
interface RelationLinkManagerInterface {
interface RelationLinkManagerInterface extends ConfigurableLinkManagerInterface {
/**
* Gets the URI that corresponds to a field.
......@@ -18,11 +18,13 @@ interface RelationLinkManagerInterface {
* The bundle name.
* @param string $field_name
* The field name.
* @param array $context
* (optional) Optional serializer/normalizer context.
*
* @return string
* The corresponding URI for the field.
*/
public function getRelationUri($entity_type, $bundle, $field_name);
public function getRelationUri($entity_type, $bundle, $field_name, $context = array());
/**
* Translates a REST URI into internal IDs.
......
......@@ -9,9 +9,11 @@
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class TypeLinkManager implements TypeLinkManagerInterface {
class TypeLinkManager extends LinkManagerBase implements TypeLinkManagerInterface {
/**
* Injected cache backend.
......@@ -21,23 +23,29 @@ class TypeLinkManager implements TypeLinkManagerInterface {
protected $cache;
/**
* The unrouted URL assembler.
* Module handler service.
*
* @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $urlAssembler;
protected $moduleHandler;
/**
* Constructor.
*
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The injected cache backend for caching type URIs.
* @param \Drupal\Core\Utility\UnroutedUrlAssemblerInterface $url_assembler
* The unrouted URL assembler.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory service.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
*/
public function __construct(CacheBackendInterface $cache, UnroutedUrlAssemblerInterface $url_assembler) {
public function __construct(CacheBackendInterface $cache, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, RequestStack $request_stack) {
$this->cache = $cache;
$this->urlAssembler = $url_assembler;
$this->configFactory = $config_factory;
$this->moduleHandler = $module_handler;
$this->requestStack = $request_stack;
}
/**
......@@ -47,20 +55,23 @@ public function __construct(CacheBackendInterface $cache, UnroutedUrlAssemblerIn
* The bundle's entity type.
* @param string $bundle
* The name of the bundle.
* @param array $context
* Context of normalizer/serializer.
*
* @return array
* @return string
* The URI that identifies this bundle.
*/
public function getTypeUri($entity_type, $bundle) {
// @todo Make the base path configurable.
return $this->urlAssembler->assemble("base:rest/type/$entity_type/$bundle", array('absolute' => TRUE));
public function getTypeUri($entity_type, $bundle, $context = array()) {
$uri = $this->getLinkDomain() . "/rest/type/$entity_type/$bundle";
$this->moduleHandler->alter('rest_type_uri', $uri, $context);
return $uri;
}
/**
* Implements \Drupal\rest\LinkManager\TypeLinkManagerInterface::getTypeInternalIds().
*/
public function getTypeInternalIds($type_uri) {
$types = $this->getTypes();
public function getTypeInternalIds($type_uri, $context = array()) {
$types = $this->getTypes($context);
if (isset($types[$type_uri])) {
return $types[$type_uri];
}
......@@ -70,15 +81,18 @@ public function getTypeInternalIds($type_uri) {
/**
* Get the array of type links.
*
* @param array $context
* Context from the normalizer/serializer operation.
*
* @return array
* An array of typed data ids (entity_type and bundle) keyed by
* corresponding type URI.
*/
protected function getTypes() {
protected function getTypes($context = array()) {
$cid = 'rest:links:types';
$cache = $this->cache->get($cid);
if (!$cache) {
$this->writeCache();
$this->writeCache($context);
$cache = $this->cache->get($cid);
}
return $cache->data;
......@@ -86,8 +100,11 @@ protected function getTypes() {
/**
* Writes the cache of type links.
*
* @param array $context
* Context from the normalizer/serializer operation.
*/
protected function writeCache() {
protected function writeCache($context = array()) {
$data = array();
// Type URIs correspond to bundles. Iterate through the bundles to get the
......@@ -101,7 +118,7 @@ protected function writeCache() {
}
foreach ($bundles as $bundle => $bundle_info) {
// Get a type URI for the bundle.
$bundle_uri = $this->getTypeUri($entity_type_id, $bundle);
$bundle_uri = $this->getTypeUri($entity_type_id, $bundle, $context);
$data[$bundle_uri] = array(
'entity_type' => $entity_type_id,
'bundle' => $bundle,
......@@ -112,4 +129,5 @@ protected function writeCache() {
// and only clear it when entity_info is cleared.
$this->cache->set('rest:links:types', $data, Cache::PERMANENT, array('entity_types'));
}
}
......@@ -7,7 +7,7 @@
namespace Drupal\rest\LinkManager;
interface TypeLinkManagerInterface {
interface TypeLinkManagerInterface extends ConfigurableLinkManagerInterface {
/**
* Gets the URI that corresponds to a bundle.
......@@ -20,21 +20,25 @@ interface TypeLinkManagerInterface {
* The bundle's entity type.
* @param $bundle
* The bundle name.
* @param array $context
* (optional) Optional serializer/normalizer context.
*
* @return string
* The corresponding URI for the bundle.
*/
public function getTypeUri($entity_type, $bundle);
public function getTypeUri($entity_type, $bundle, $context = array());
/**
* Get a bundle's Typed Data IDs based on a URI.
*
* @param string $type_uri
* The type URI.
* @param array $context
* Context from the normalizer/serializer operation.
*
* @return array | boolean
* If the URI matches a bundle, returns an array containing entity_type and
* bundle. Otherwise, returns false.
*/
public function getTypeInternalIds($type_uri);
public function getTypeInternalIds($type_uri, $context = array());
}
<?php
/**
* @file
* Contains \Drupal\rest\Tests\RestLinkManagerTest.
*/
namespace Drupal\rest\Tests;
use Drupal\Core\Url;
use Drupal\simpletest\KernelTestBase;
/**
* Tests that REST type and relation link managers work as expected
* @group rest
*/
class RestLinkManagerTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['rest', 'rest_test', 'system'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', ['router']);
\Drupal::service('router.builder')->rebuild();
}
/**
* Tests that type hooks work as expected.
*/
public function testRestLinkManagers() {
\Drupal::moduleHandler()->invoke('rest', 'install');
/* @var \Drupal\rest\LinkManager\TypeLinkManagerInterface $type_manager */
$type_manager = \Drupal::service('rest.link_manager.type');
$base = Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString();
$link = $type_manager->getTypeUri('node', 'page');
$this->assertEqual($link, $base . 'rest/type/node/page');
// Now with optional context.
$link = $type_manager->getTypeUri('node', 'page', ['rest_test' => TRUE]);
$this->assertEqual($link, 'rest_test_type');
/* @var \Drupal\rest\LinkManager\RelationLinkManagerInterface $relation_manager */
$relation_manager = \Drupal::service('rest.link_manager.relation');
$link = $relation_manager->getRelationUri('node', 'page', 'field_ref');
$this->assertEqual($link, $base . 'rest/relation/node/page/field_ref');
// Now with optional context.
$link = $relation_manager->getRelationUri('node', 'page', 'foobar', ['rest_test' => TRUE]);
$this->assertEqual($link, 'rest_test_relation');
}
/**
* Tests that type hooks work as expected even without install hook.
*/
public function testRestLinkManagersNoInstallHook() {
/* @var \Drupal\rest\LinkManager\TypeLinkManagerInterface $type_manager */
$type_manager = \Drupal::service('rest.link_manager.type');
$base = Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString();
$link = $type_manager->getTypeUri('node', 'page');
$this->assertEqual($link, $base . 'rest/type/node/page');
// Now with optional context.
$link = $type_manager->getTypeUri('node', 'page', ['rest_test' => TRUE]);
$this->assertEqual($link, 'rest_test_type');
/* @var \Drupal\rest\LinkManager\RelationLinkManagerInterface $relation_manager */
$relation_manager = \Drupal::service('rest.link_manager.relation');
$link = $relation_manager->getRelationUri('node', 'page', 'field_ref');
$this->assertEqual($link, $base . 'rest/relation/node/page/field_ref');
// Now with optional context.
$link = $relation_manager->getRelationUri('node', 'page', 'foobar', ['rest_test' => TRUE]);
$this->assertEqual($link, 'rest_test_relation');
}
/**
* Tests \Drupal\rest\LinkManager\LinkManager::setLinkDomain().
*/
public function testRestLinkManagersSetLinkDomain() {
/* @var \Drupal\rest\LinkManager\LinkManager $link_manager */
$link_manager = \Drupal::service('rest.link_manager');
$link_manager->setLinkDomain('http://example.com/');
$link = $link_manager->getTypeUri('node', 'page');
$this->assertEqual($link, 'http://example.com/rest/type/node/page');