summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authoreffulgentsia <alex.bronstein@acquia.com>2017-01-30 21:53:34 -0800
committereffulgentsia <alex.bronstein@acquia.com>2017-01-30 21:53:34 -0800
commitbfaf6b6e0f2c7057ae78299093870d80a91e1045 (patch)
tree6ca704fa520da187c98571f91996e99fd12a872c
parent414574e17330342d94122a2b281a02d18ad1eaf2 (diff)
downloaddrupal-bfaf6b6e0f2c7057ae78299093870d80a91e1045.tar.gz
drupal-bfaf6b6e0f2c7057ae78299093870d80a91e1045.zip
Issue #2758897 by Wim Leers, damiankloip, larowlan: Move rest module's "link manager" services to serialization module
-rw-r--r--core/modules/hal/hal.info.yml1
-rw-r--r--core/modules/hal/hal.services.yml6
-rw-r--r--core/modules/hal/src/Normalizer/ContentEntityNormalizer.php6
-rw-r--r--core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php6
-rw-r--r--core/modules/hal/src/Normalizer/FileEntityNormalizer.php4
-rw-r--r--core/modules/hal/tests/src/Kernel/FileNormalizeTest.php6
-rw-r--r--core/modules/hal/tests/src/Kernel/NormalizerTestBase.php8
-rw-r--r--core/modules/rest/config/install/rest.settings.yml4
-rw-r--r--core/modules/rest/config/schema/rest.schema.yml1
-rw-r--r--core/modules/rest/rest.api.php10
-rw-r--r--core/modules/rest/rest.services.yml13
-rw-r--r--core/modules/rest/src/LinkManager/ConfigurableLinkManagerInterface.php19
-rw-r--r--core/modules/rest/src/LinkManager/LinkManager.php72
-rw-r--r--core/modules/rest/src/LinkManager/LinkManagerBase.php57
-rw-r--r--core/modules/rest/src/LinkManager/LinkManagerInterface.php17
-rw-r--r--core/modules/rest/src/LinkManager/RelationLinkManager.php143
-rw-r--r--core/modules/rest/src/LinkManager/RelationLinkManagerInterface.php40
-rw-r--r--core/modules/rest/src/LinkManager/TypeLinkManager.php150
-rw-r--r--core/modules/rest/src/LinkManager/TypeLinkManagerInterface.php41
-rw-r--r--core/modules/rest/tests/modules/rest_test/rest_test.module4
-rw-r--r--core/modules/rest/tests/src/Kernel/RestLinkManagerTest.php85
-rw-r--r--core/modules/serialization/config/install/serialization.settings.yml3
-rw-r--r--core/modules/serialization/config/schema/serialization.schema.yml8
-rw-r--r--core/modules/serialization/serialization.api.php62
-rw-r--r--core/modules/serialization/serialization.install43
-rw-r--r--core/modules/serialization/serialization.services.yml10
-rw-r--r--core/modules/serialization/src/LinkManager/ConfigurableLinkManagerInterface.php20
-rw-r--r--core/modules/serialization/src/LinkManager/LinkManager.php71
-rw-r--r--core/modules/serialization/src/LinkManager/LinkManagerBase.php58
-rw-r--r--core/modules/serialization/src/LinkManager/LinkManagerInterface.php18
-rw-r--r--core/modules/serialization/src/LinkManager/RelationLinkManager.php144
-rw-r--r--core/modules/serialization/src/LinkManager/RelationLinkManagerInterface.php39
-rw-r--r--core/modules/serialization/src/LinkManager/TypeLinkManager.php150
-rw-r--r--core/modules/serialization/src/LinkManager/TypeLinkManagerInterface.php40
-rw-r--r--core/modules/serialization/tests/fixtures/update/drupal-8.rest-serialization_update_8301.phpbin0 -> 4901 bytes
-rw-r--r--core/modules/serialization/tests/fixtures/update/drupal-8.serialization-serialization_update_8301.php37
-rw-r--r--core/modules/serialization/tests/serialization_test/serialization_test.module24
-rw-r--r--core/modules/serialization/tests/src/Functional/Update/CreateSerializationSettingsForLinkDomainUpdateTest.php47
-rw-r--r--core/modules/serialization/tests/src/Functional/Update/MigrateLinkDomainSettingFromRestToSerializationUpdateTest.php53
-rw-r--r--core/modules/serialization/tests/src/Kernel/SerializationLinkManagerTest.php74
40 files changed, 987 insertions, 607 deletions
diff --git a/core/modules/hal/hal.info.yml b/core/modules/hal/hal.info.yml
index 4cf0c7ead66..2d87eff9d29 100644
--- a/core/modules/hal/hal.info.yml
+++ b/core/modules/hal/hal.info.yml
@@ -5,5 +5,4 @@ package: Web services
version: VERSION
core: 8.x
dependencies:
- - rest
- serialization
diff --git a/core/modules/hal/hal.services.yml b/core/modules/hal/hal.services.yml
index 7e40df0d5b8..c8c9a2cd47f 100644
--- a/core/modules/hal/hal.services.yml
+++ b/core/modules/hal/hal.services.yml
@@ -1,7 +1,7 @@
services:
serializer.normalizer.entity_reference_item.hal:
class: Drupal\hal\Normalizer\EntityReferenceItemNormalizer
- arguments: ['@rest.link_manager', '@serializer.entity_resolver']
+ arguments: ['@serialization.link_manager', '@serializer.entity_resolver']
tags:
- { name: normalizer, priority: 10 }
serializer.normalizer.field_item.hal:
@@ -16,10 +16,10 @@ services:
class: Drupal\hal\Normalizer\FileEntityNormalizer
tags:
- { name: normalizer, priority: 20 }
- arguments: ['@entity.manager', '@http_client', '@rest.link_manager', '@module_handler']
+ arguments: ['@entity.manager', '@http_client', '@serialization.link_manager', '@module_handler']
serializer.normalizer.entity.hal:
class: Drupal\hal\Normalizer\ContentEntityNormalizer
- arguments: ['@rest.link_manager', '@entity.manager', '@module_handler']
+ arguments: ['@serialization.link_manager', '@entity.manager', '@module_handler']
tags:
- { name: normalizer, priority: 10 }
serializer.encoder.hal:
diff --git a/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php b/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php
index fce3ddca401..88eb36cdcd3 100644
--- a/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php
+++ b/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php
@@ -6,7 +6,7 @@ use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\rest\LinkManager\LinkManagerInterface;
+use Drupal\serialization\LinkManager\LinkManagerInterface;
use Drupal\serialization\Normalizer\FieldableEntityNormalizerTrait;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
@@ -27,7 +27,7 @@ class ContentEntityNormalizer extends NormalizerBase {
/**
* The hypermedia link manager.
*
- * @var \Drupal\rest\LinkManager\LinkManagerInterface
+ * @var \Drupal\serialization\LinkManager\LinkManagerInterface
*/
protected $linkManager;
@@ -41,7 +41,7 @@ class ContentEntityNormalizer extends NormalizerBase {
/**
* Constructs an ContentEntityNormalizer object.
*
- * @param \Drupal\rest\LinkManager\LinkManagerInterface $link_manager
+ * @param \Drupal\serialization\LinkManager\LinkManagerInterface $link_manager
* The hypermedia link manager.
*/
public function __construct(LinkManagerInterface $link_manager, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler) {
diff --git a/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
index 6c73256e147..4dea76c9179 100644
--- a/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
+++ b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
@@ -3,7 +3,7 @@
namespace Drupal\hal\Normalizer;
use Drupal\Core\Entity\FieldableEntityInterface;
-use Drupal\rest\LinkManager\LinkManagerInterface;
+use Drupal\serialization\LinkManager\LinkManagerInterface;
use Drupal\serialization\EntityResolver\EntityResolverInterface;
use Drupal\serialization\EntityResolver\UuidReferenceInterface;
@@ -22,7 +22,7 @@ class EntityReferenceItemNormalizer extends FieldItemNormalizer implements UuidR
/**
* The hypermedia link manager.
*
- * @var \Drupal\rest\LinkManager\LinkManagerInterface
+ * @var \Drupal\serialization\LinkManager\LinkManagerInterface
*/
protected $linkManager;
@@ -36,7 +36,7 @@ class EntityReferenceItemNormalizer extends FieldItemNormalizer implements UuidR
/**
* Constructs an EntityReferenceItemNormalizer object.
*
- * @param \Drupal\rest\LinkManager\LinkManagerInterface $link_manager
+ * @param \Drupal\serialization\LinkManager\LinkManagerInterface $link_manager
* The hypermedia link manager.
* @param \Drupal\serialization\EntityResolver\EntityResolverInterface $entity_Resolver
* The entity resolver.
diff --git a/core/modules/hal/src/Normalizer/FileEntityNormalizer.php b/core/modules/hal/src/Normalizer/FileEntityNormalizer.php
index 46c609451df..c7c686fde83 100644
--- a/core/modules/hal/src/Normalizer/FileEntityNormalizer.php
+++ b/core/modules/hal/src/Normalizer/FileEntityNormalizer.php
@@ -4,7 +4,7 @@ namespace Drupal\hal\Normalizer;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\rest\LinkManager\LinkManagerInterface;
+use Drupal\serialization\LinkManager\LinkManagerInterface;
use GuzzleHttp\ClientInterface;
/**
@@ -33,7 +33,7 @@ class FileEntityNormalizer extends ContentEntityNormalizer {
* The entity manager.
* @param \GuzzleHttp\ClientInterface $http_client
* The HTTP Client.
- * @param \Drupal\rest\LinkManager\LinkManagerInterface $link_manager
+ * @param \Drupal\serialization\LinkManager\LinkManagerInterface $link_manager
* The hypermedia link manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
diff --git a/core/modules/hal/tests/src/Kernel/FileNormalizeTest.php b/core/modules/hal/tests/src/Kernel/FileNormalizeTest.php
index 42d7a36a6f5..cacef30fff6 100644
--- a/core/modules/hal/tests/src/Kernel/FileNormalizeTest.php
+++ b/core/modules/hal/tests/src/Kernel/FileNormalizeTest.php
@@ -7,9 +7,9 @@ use Drupal\file\Entity\File;
use Drupal\hal\Encoder\JsonEncoder;
use Drupal\hal\Normalizer\FieldItemNormalizer;
use Drupal\hal\Normalizer\FileEntityNormalizer;
-use Drupal\rest\LinkManager\LinkManager;
-use Drupal\rest\LinkManager\RelationLinkManager;
-use Drupal\rest\LinkManager\TypeLinkManager;
+use Drupal\serialization\LinkManager\LinkManager;
+use Drupal\serialization\LinkManager\RelationLinkManager;
+use Drupal\serialization\LinkManager\TypeLinkManager;
use Symfony\Component\Serializer\Serializer;
diff --git a/core/modules/hal/tests/src/Kernel/NormalizerTestBase.php b/core/modules/hal/tests/src/Kernel/NormalizerTestBase.php
index 58674763c2c..1fc5e4c0c69 100644
--- a/core/modules/hal/tests/src/Kernel/NormalizerTestBase.php
+++ b/core/modules/hal/tests/src/Kernel/NormalizerTestBase.php
@@ -10,9 +10,9 @@ use Drupal\hal\Normalizer\EntityReferenceItemNormalizer;
use Drupal\hal\Normalizer\FieldItemNormalizer;
use Drupal\hal\Normalizer\FieldNormalizer;
use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\rest\LinkManager\LinkManager;
-use Drupal\rest\LinkManager\RelationLinkManager;
-use Drupal\rest\LinkManager\TypeLinkManager;
+use Drupal\serialization\LinkManager\LinkManager;
+use Drupal\serialization\LinkManager\RelationLinkManager;
+use Drupal\serialization\LinkManager\TypeLinkManager;
use Drupal\serialization\EntityResolver\ChainEntityResolver;
use Drupal\serialization\EntityResolver\TargetIdResolver;
use Drupal\serialization\EntityResolver\UuidResolver;
@@ -30,7 +30,7 @@ abstract class NormalizerTestBase extends KernelTestBase {
*
* @var array
*/
- public static $modules = ['entity_test', 'field', 'hal', 'language', 'rest', 'serialization', 'system', 'text', 'user', 'filter'];
+ public static $modules = ['entity_test', 'field', 'hal', 'language', 'serialization', 'system', 'text', 'user', 'filter'];
/**
* The mock serializer.
diff --git a/core/modules/rest/config/install/rest.settings.yml b/core/modules/rest/config/install/rest.settings.yml
index eb3da2df4ca..8f70c6997d1 100644
--- a/core/modules/rest/config/install/rest.settings.yml
+++ b/core/modules/rest/config/install/rest.settings.yml
@@ -1,7 +1,3 @@
-# Set the domain for REST type and relation links.
-# If left blank, the site's domain will be used.
-link_domain: ~
-
# Before Drupal 8.2, EntityResource used permissions as well as the entity
# access system for access checking. This was confusing, and it only did this
# for historical reasons. New Drupal installations opt out from this by default
diff --git a/core/modules/rest/config/schema/rest.schema.yml b/core/modules/rest/config/schema/rest.schema.yml
index 2c255ab88cd..49b4b2d9426 100644
--- a/core/modules/rest/config/schema/rest.schema.yml
+++ b/core/modules/rest/config/schema/rest.schema.yml
@@ -3,6 +3,7 @@ rest.settings:
type: config_object
label: 'REST settings'
mapping:
+ # @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0.
link_domain:
type: string
label: 'Domain of the relation'
diff --git a/core/modules/rest/rest.api.php b/core/modules/rest/rest.api.php
index fb8993d2680..9bf6921c09b 100644
--- a/core/modules/rest/rest.api.php
+++ b/core/modules/rest/rest.api.php
@@ -31,6 +31,9 @@ function hook_rest_resource_alter(&$definitions) {
/**
* Alter the REST type URI.
*
+ * @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. Use
+ * hook_serialization_type_uri_alter() instead. This exists solely for BC.
+ *
* Modules may wish to alter the type URI generated for a resource based on the
* context of the serializer/normalizer operation.
*
@@ -46,7 +49,7 @@ function hook_rest_resource_alter(&$definitions) {
*/
function hook_rest_type_uri_alter(&$uri, $context = array()) {
if ($context['mymodule'] == TRUE) {
- $base = \Drupal::config('rest.settings')->get('link_domain');
+ $base = \Drupal::config('serialization.settings')->get('link_domain');
$uri = str_replace($base, 'http://mymodule.domain', $uri);
}
}
@@ -55,6 +58,9 @@ function hook_rest_type_uri_alter(&$uri, $context = array()) {
/**
* Alter the REST relation URI.
*
+ * @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. Use
+ * hook_serialization_relation_uri_alter() instead. This exists solely for BC.
+ *
* Modules may wish to alter the relation URI generated for a resource based on
* the context of the serializer/normalizer operation.
*
@@ -70,7 +76,7 @@ function hook_rest_type_uri_alter(&$uri, $context = array()) {
*/
function hook_rest_relation_uri_alter(&$uri, $context = array()) {
if ($context['mymodule'] == TRUE) {
- $base = \Drupal::config('rest.settings')->get('link_domain');
+ $base = \Drupal::config('serialization.settings')->get('link_domain');
$uri = str_replace($base, 'http://mymodule.domain', $uri);
}
}
diff --git a/core/modules/rest/rest.services.yml b/core/modules/rest/rest.services.yml
index 81eb4510894..2def91e992d 100644
--- a/core/modules/rest/rest.services.yml
+++ b/core/modules/rest/rest.services.yml
@@ -11,15 +11,22 @@ services:
# @todo Remove this service in Drupal 9.0.0.
access_check.rest.csrf:
alias: access_check.header.csrf
+ # Link managers.
+ # @deprecated in Drupal 8.3.x and will be removed before 9.0.0. Use
+ # serialization.link_manager instead.
rest.link_manager:
+ parent: serialization.link_manager
class: Drupal\rest\LinkManager\LinkManager
- arguments: ['@rest.link_manager.type', '@rest.link_manager.relation']
+ # @deprecated in Drupal 8.3.x and will be removed before 9.0.0. Use
+ # serialization.link_manager.type instead.
rest.link_manager.type:
+ parent: serialization.link_manager.type
class: Drupal\rest\LinkManager\TypeLinkManager
- arguments: ['@cache.default', '@module_handler', '@config.factory', '@request_stack', '@entity_type.bundle.info']
+ # @deprecated in Drupal 8.3.x and will be removed before 9.0.0. Use
+ # serialization.link_manager.relation instead.
rest.link_manager.relation:
+ parent: serialization.link_manager.relation
class: Drupal\rest\LinkManager\RelationLinkManager
- arguments: ['@cache.default', '@entity.manager', '@module_handler', '@config.factory', '@request_stack']
rest.resource_routes:
class: Drupal\rest\Routing\ResourceRoutes
arguments: ['@plugin.manager.rest', '@entity_type.manager', '@logger.channel.rest']
diff --git a/core/modules/rest/src/LinkManager/ConfigurableLinkManagerInterface.php b/core/modules/rest/src/LinkManager/ConfigurableLinkManagerInterface.php
index c2eb1f136b1..c73f5f0aef2 100644
--- a/core/modules/rest/src/LinkManager/ConfigurableLinkManagerInterface.php
+++ b/core/modules/rest/src/LinkManager/ConfigurableLinkManagerInterface.php
@@ -2,19 +2,10 @@
namespace Drupal\rest\LinkManager;
+use Drupal\serialization\LinkManager\ConfigurableLinkManagerInterface as MovedConfigurableLinkManagerInterface;
+
/**
- * Defines an interface for a link manager with a configurable domain.
+ * @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This has
+ * been moved to the serialization module. This exists solely for BC.
*/
-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);
-
-}
+interface ConfigurableLinkManagerInterface extends MovedConfigurableLinkManagerInterface {}
diff --git a/core/modules/rest/src/LinkManager/LinkManager.php b/core/modules/rest/src/LinkManager/LinkManager.php
index bd94a6580ee..1b450c50a6c 100644
--- a/core/modules/rest/src/LinkManager/LinkManager.php
+++ b/core/modules/rest/src/LinkManager/LinkManager.php
@@ -2,70 +2,10 @@
namespace Drupal\rest\LinkManager;
-class LinkManager implements LinkManagerInterface {
+use Drupal\serialization\LinkManager\LinkManager as MovedLinkManager;
- /**
- * The type link manager.
- *
- * @var \Drupal\rest\LinkManager\TypeLinkManagerInterface
- */
- protected $typeLinkManager;
-
- /**
- * The relation link manager.
- *
- * @var \Drupal\rest\LinkManager\RelationLinkManagerInterface
- */
- protected $relationLinkManager;
-
- /**
- * Constructor.
- *
- * @param \Drupal\rest\LinkManager\TypeLinkManagerInterface $type_link_manager
- * Manager for handling bundle URIs.
- * @param \Drupal\rest\LinkManager\RelationLinkManagerInterface $relation_link_manager
- * Manager for handling bundle URIs.
- */
- public function __construct(TypeLinkManagerInterface $type_link_manager, RelationLinkManagerInterface $relation_link_manager) {
- $this->typeLinkManager = $type_link_manager;
- $this->relationLinkManager = $relation_link_manager;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeUri($entity_type, $bundle, $context = array()) {
- return $this->typeLinkManager->getTypeUri($entity_type, $bundle, $context);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeInternalIds($type_uri, $context = array()) {
- return $this->typeLinkManager->getTypeInternalIds($type_uri, $context);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRelationUri($entity_type, $bundle, $field_name, $context = array()) {
- return $this->relationLinkManager->getRelationUri($entity_type, $bundle, $field_name, $context);
- }
-
- /**
- * {@inheritdoc}
- */
- 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;
- }
-
-}
+/**
+ * @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This has
+ * been moved to the serialization module. This exists solely for BC.
+ */
+class LinkManager extends MovedLinkManager implements LinkManagerInterface {}
diff --git a/core/modules/rest/src/LinkManager/LinkManagerBase.php b/core/modules/rest/src/LinkManager/LinkManagerBase.php
index 0896a80f73d..13f8b53ae3f 100644
--- a/core/modules/rest/src/LinkManager/LinkManagerBase.php
+++ b/core/modules/rest/src/LinkManager/LinkManagerBase.php
@@ -2,57 +2,10 @@
namespace Drupal\rest\LinkManager;
+use Drupal\serialization\LinkManager\LinkManagerBase as MovedLinkManagerBase;
+
/**
- * Defines an abstract base-class for REST link manager objects.
+ * @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This has
+ * been moved to the serialization module. This exists solely for BC.
*/
-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;
- }
-
-}
+abstract class LinkManagerBase extends MovedLinkManagerBase {}
diff --git a/core/modules/rest/src/LinkManager/LinkManagerInterface.php b/core/modules/rest/src/LinkManager/LinkManagerInterface.php
index 1bd04ff50b9..26f5dc473dd 100644
--- a/core/modules/rest/src/LinkManager/LinkManagerInterface.php
+++ b/core/modules/rest/src/LinkManager/LinkManagerInterface.php
@@ -2,17 +2,10 @@
namespace Drupal\rest\LinkManager;
+use Drupal\serialization\LinkManager\LinkManagerInterface as MovedLinkManagerInterface;
+
/**
- * Interface implemented by link managers.
- *
- * There are no explicit methods on the manager interface. Instead link managers
- * broker the interactions of the different components, and therefore must
- * implement each component interface, which is enforced by this interface
- * extending all of the component ones.
- *
- * While a link manager may directly implement these interface methods with
- * custom logic, it is expected to be more common for plugin managers to proxy
- * the method invocations to the respective components.
+ * @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This has
+ * been moved to the serialization module. This exists solely for BC.
*/
-interface LinkManagerInterface extends TypeLinkManagerInterface, RelationLinkManagerInterface {
-}
+interface LinkManagerInterface extends MovedLinkManagerInterface {}
diff --git a/core/modules/rest/src/LinkManager/RelationLinkManager.php b/core/modules/rest/src/LinkManager/RelationLinkManager.php
index 297ffd9a0c2..a29eb9a8927 100644
--- a/core/modules/rest/src/LinkManager/RelationLinkManager.php
+++ b/core/modules/rest/src/LinkManager/RelationLinkManager.php
@@ -2,141 +2,10 @@
namespace Drupal\rest\LinkManager;
-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\Extension\ModuleHandlerInterface;
-use Symfony\Component\HttpFoundation\RequestStack;
+use Drupal\serialization\LinkManager\RelationLinkManager as MovedLinkRelationManager;
-class RelationLinkManager extends LinkManagerBase implements RelationLinkManagerInterface {
-
- /**
- * @var \Drupal\Core\Cache\CacheBackendInterface;
- */
- protected $cache;
-
- /**
- * Entity manager.
- *
- * @var \Drupal\Core\Entity\EntityManagerInterface
- */
- protected $entityManager;
-
- /**
- * Module handler service.
- *
- * @var \Drupal\Core\Extension\ModuleHandlerInterface
- */
- protected $moduleHandler;
-
- /**
- * Constructor.
- *
- * @param \Drupal\Core\Cache\CacheBackendInterface $cache
- * The cache of relation URIs and their associated Typed Data IDs.
- * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
- * The entity manager.
- * @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, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, RequestStack $request_stack) {
- $this->cache = $cache;
- $this->entityManager = $entity_manager;
- $this->configFactory = $config_factory;
- $this->moduleHandler = $module_handler;
- $this->requestStack = $request_stack;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRelationUri($entity_type, $bundle, $field_name, $context = array()) {
- // Per the interface documention of this method, the returned URI may
- // optionally also serve as the URL of a documentation page about this
- // field. However, the REST module does not currently implement such
- // a documentation page. Therefore, we return a URI assembled relative to
- // the site's base URL, which is sufficient to uniquely identify the site's
- // entity type + bundle + field for use in hypermedia formats, but we do
- // not take into account unclean URLs, language prefixing, or anything else
- // that would be required for Drupal to be able to respond with content
- // at this URL. If a module is installed that adds such content, but
- // requires this URL to be different (e.g., include a language prefix),
- // then the module must also override the RelationLinkManager class/service
- // to return the desired URL.
- $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, $context = array()) {
- $relations = $this->getRelations($context);
- if (isset($relations[$relation_uri])) {
- return $relations[$relation_uri];
- }
- return FALSE;
- }
-
- /**
- * Get the array of relation links.
- *
- * Any field can be handled as a relation simply by changing how it is
- * normalized. Therefore, there is no prior knowledge that can be used here
- * to determine which fields to assign relation URIs. Instead, each field,
- * 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($context = array()) {
- $cid = 'rest:links:relations';
- $cache = $this->cache->get($cid);
- if (!$cache) {
- $this->writeCache($context);
- $cache = $this->cache->get($cid);
- }
- return $cache->data;
- }
-
- /**
- * Writes the cache of relation links.
- *
- * @param array $context
- * Context from the normalizer/serializer operation.
- */
- 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(), $context);
- $data[$relation_uri] = array(
- 'entity_type' => $entity_type,
- 'bundle' => $bundle,
- 'field_name' => $field_definition->getName(),
- );
- }
- }
- }
- }
- // These URIs only change when field info changes, so cache it permanently
- // and only clear it when the fields cache is cleared.
- $this->cache->set('rest:links:relations', $data, Cache::PERMANENT, array('entity_field_info'));
- }
-
-}
+/**
+ * @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This has
+ * been moved to the serialization module. This exists solely for BC.
+ */
+class RelationLinkManager extends MovedLinkRelationManager implements RelationLinkManagerInterface {}
diff --git a/core/modules/rest/src/LinkManager/RelationLinkManagerInterface.php b/core/modules/rest/src/LinkManager/RelationLinkManagerInterface.php
index 53cd03991fb..c171b764eeb 100644
--- a/core/modules/rest/src/LinkManager/RelationLinkManagerInterface.php
+++ b/core/modules/rest/src/LinkManager/RelationLinkManagerInterface.php
@@ -2,38 +2,10 @@
namespace Drupal\rest\LinkManager;
-interface RelationLinkManagerInterface extends ConfigurableLinkManagerInterface {
+use Drupal\serialization\LinkManager\RelationLinkManagerInterface as MovedRelationLinkManagerInterface;
- /**
- * Gets the URI that corresponds to a field.
- *
- * When using hypermedia formats, this URI can be used to indicate which
- * field the data represents. Documentation about this field can also be
- * provided at this URI.
- *
- * @param string $entity_type
- * The bundle's entity type.
- * @param string $bundle
- * 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, $context = array());
-
- /**
- * Translates a REST URI into internal IDs.
- *
- * @param string $relation_uri
- * Relation URI to transform into internal IDs
- *
- * @return array
- * Array with keys 'entity_type', 'bundle' and 'field_name'.
- */
- public function getRelationInternalIds($relation_uri);
-
-}
+/**
+ * @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This has
+ * been moved to the serialization module. This exists solely for BC.
+ */
+interface RelationLinkManagerInterface extends MovedRelationLinkManagerInterface {}
diff --git a/core/modules/rest/src/LinkManager/TypeLinkManager.php b/core/modules/rest/src/LinkManager/TypeLinkManager.php
index 3b0c8a23a8f..ac514eb0b0a 100644
--- a/core/modules/rest/src/LinkManager/TypeLinkManager.php
+++ b/core/modules/rest/src/LinkManager/TypeLinkManager.php
@@ -2,148 +2,10 @@
namespace Drupal\rest\LinkManager;
-use Drupal\Core\Cache\Cache;
-use Drupal\Core\Cache\CacheBackendInterface;
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Config\Entity\ConfigEntityInterface;
-use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Symfony\Component\HttpFoundation\RequestStack;
+use Drupal\serialization\LinkManager\TypeLinkManager as MovedTypeLinkManager;
-class TypeLinkManager extends LinkManagerBase implements TypeLinkManagerInterface {
-
- /**
- * Injected cache backend.
- *
- * @var \Drupal\Core\Cache\CacheBackendInterface;
- */
- protected $cache;
-
- /**
- * Module handler service.
- *
- * @var \Drupal\Core\Extension\ModuleHandlerInterface
- */
- protected $moduleHandler;
-
- /**
- * The bundle info service.
- *
- * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
- */
- protected $bundleInfoService;
-
- /**
- * Constructor.
- *
- * @param \Drupal\Core\Cache\CacheBackendInterface $cache
- * The injected cache backend for caching type URIs.
- * @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.
- * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info_service
- * The bundle info service.
- */
- public function __construct(CacheBackendInterface $cache, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, RequestStack $request_stack, EntityTypeBundleInfoInterface $bundle_info_service) {
- $this->cache = $cache;
- $this->configFactory = $config_factory;
- $this->moduleHandler = $module_handler;
- $this->requestStack = $request_stack;
- $this->bundleInfoService = $bundle_info_service;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeUri($entity_type, $bundle, $context = array()) {
- // Per the interface documention of this method, the returned URI may
- // optionally also serve as the URL of a documentation page about this
- // bundle. However, the REST module does not currently implement such
- // a documentation page. Therefore, we return a URI assembled relative to
- // the site's base URL, which is sufficient to uniquely identify the site's
- // entity type and bundle for use in hypermedia formats, but we do not
- // take into account unclean URLs, language prefixing, or anything else
- // that would be required for Drupal to be able to respond with content
- // at this URL. If a module is installed that adds such content, but
- // requires this URL to be different (e.g., include a language prefix),
- // then the module must also override the TypeLinkManager class/service to
- // return the desired URL.
- $uri = $this->getLinkDomain() . "/rest/type/$entity_type/$bundle";
- $this->moduleHandler->alter('rest_type_uri', $uri, $context);
- return $uri;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeInternalIds($type_uri, $context = array()) {
- $types = $this->getTypes($context);
- if (isset($types[$type_uri])) {
- return $types[$type_uri];
- }
- return FALSE;
- }
-
- /**
- * 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($context = array()) {
- $cid = 'rest:links:types';
- $cache = $this->cache->get($cid);
- if (!$cache) {
- $data = $this->writeCache($context);
- }
- else {
- $data = $cache->data;
- }
- return $data;
- }
-
- /**
- * Writes the cache 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 writeCache($context = array()) {
- $data = array();
-
- // Type URIs correspond to bundles. Iterate through the bundles to get the
- // URI and data for them.
- $entity_types = \Drupal::entityManager()->getDefinitions();
- foreach ($this->bundleInfoService->getAllBundleInfo() as $entity_type_id => $bundles) {
- // Only content entities are supported currently.
- // @todo Consider supporting config entities.
- if ($entity_types[$entity_type_id]->entityClassImplements(ConfigEntityInterface::class)) {
- continue;
- }
- foreach ($bundles as $bundle => $bundle_info) {
- // Get a type URI for the bundle.
- $bundle_uri = $this->getTypeUri($entity_type_id, $bundle, $context);
- $data[$bundle_uri] = array(
- 'entity_type' => $entity_type_id,
- 'bundle' => $bundle,
- );
- }
- }
- // These URIs only change when entity info changes, so cache it permanently
- // and only clear it when entity_info is cleared.
- $this->cache->set('rest:links:types', $data, Cache::PERMANENT, array('entity_types'));
- return $data;
- }
-
-}
+/**
+ * @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This has
+ * been moved to the serialization module. This exists solely for BC.
+ */
+class TypeLinkManager extends MovedTypeLinkManager implements TypeLinkManagerInterface {}
diff --git a/core/modules/rest/src/LinkManager/TypeLinkManagerInterface.php b/core/modules/rest/src/LinkManager/TypeLinkManagerInterface.php
index 484ca76f156..e4abf1d2e93 100644
--- a/core/modules/rest/src/LinkManager/TypeLinkManagerInterface.php
+++ b/core/modules/rest/src/LinkManager/TypeLinkManagerInterface.php
@@ -2,39 +2,10 @@
namespace Drupal\rest\LinkManager;
-interface TypeLinkManagerInterface extends ConfigurableLinkManagerInterface {
+use Drupal\serialization\LinkManager\TypeLinkManagerInterface as MovedTypeLinkManagerInterface;
- /**
- * Gets the URI that corresponds to a bundle.
- *
- * When using hypermedia formats, this URI can be used to indicate which
- * bundle the data represents. Documentation about required and optional
- * fields can also be provided at this URI.
- *
- * @param $entity_type
- * 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, $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, $context = array());
-
-}
+/**
+ * @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This has
+ * been moved to the serialization module. This exists solely for BC.
+ */
+interface TypeLinkManagerInterface extends MovedTypeLinkManagerInterface {}
diff --git a/core/modules/rest/tests/modules/rest_test/rest_test.module b/core/modules/rest/tests/modules/rest_test/rest_test.module
index 01511ea1e0b..98f9b5a129d 100644
--- a/core/modules/rest/tests/modules/rest_test/rest_test.module
+++ b/core/modules/rest/tests/modules/rest_test/rest_test.module
@@ -12,6 +12,8 @@ use Drupal\Core\Access\AccessResult;
/**
* Implements hook_rest_type_uri_alter().
+ *
+ * @deprecated Kept only for BC test coverage, see \Drupal\Tests\serialization\Kernel\SerializationLinkManagerTest::testGetTypeUri().
*/
function rest_test_rest_type_uri_alter(&$uri, $context = array()) {
if (!empty($context['rest_test'])) {
@@ -21,6 +23,8 @@ function rest_test_rest_type_uri_alter(&$uri, $context = array()) {
/**
* Implements hook_rest_relation_uri_alter().
+ *
+ * @deprecated Kept only for BC test coverage, see \Drupal\Tests\serialization\Kernel\SerializationLinkManagerTest::testGetRelationUri().
*/
function rest_test_rest_relation_uri_alter(&$uri, $context = array()) {
if (!empty($context['rest_test'])) {
diff --git a/core/modules/rest/tests/src/Kernel/RestLinkManagerTest.php b/core/modules/rest/tests/src/Kernel/RestLinkManagerTest.php
deleted file mode 100644
index ab558e5761c..00000000000
--- a/core/modules/rest/tests/src/Kernel/RestLinkManagerTest.php
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-
-namespace Drupal\Tests\rest\Kernel;
-
-use Drupal\Core\Url;
-use Drupal\KernelTests\KernelTestBase;
-
-/**
- * Tests that REST type and relation link managers work as expected
- * @group rest
- */
-class RestLinkManagerTest extends KernelTestBase {
-
- /**
- * {@inheritdoc}
- */
- public static $modules = ['serialization', 'rest', 'rest_test', 'system'];
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
- \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');
- $link = $link_manager->getRelationUri('node', 'page', 'field_ref');
- $this->assertEqual($link, 'http://example.com/rest/relation/node/page/field_ref');
- }
-
-}
diff --git a/core/modules/serialization/config/install/serialization.settings.yml b/core/modules/serialization/config/install/serialization.settings.yml
new file mode 100644
index 00000000000..efe9deb9dda
--- /dev/null
+++ b/core/modules/serialization/config/install/serialization.settings.yml
@@ -0,0 +1,3 @@
+# Set the domain for Serialization type and relation links.
+# If left blank, the site's domain will be used.
+link_domain: ~
diff --git a/core/modules/serialization/config/schema/serialization.schema.yml b/core/modules/serialization/config/schema/serialization.schema.yml
new file mode 100644
index 00000000000..349499aa21f
--- /dev/null
+++ b/core/modules/serialization/config/schema/serialization.schema.yml
@@ -0,0 +1,8 @@
+# Schema for the configuration files of the Serialization module.
+serialization.settings:
+ type: config_object
+ label: 'Serialization settings'
+ mapping:
+ link_domain:
+ type: string
+ label: 'Domain of the relation'
diff --git a/core/modules/serialization/serialization.api.php b/core/modules/serialization/serialization.api.php
new file mode 100644
index 00000000000..a9ced724362
--- /dev/null
+++ b/core/modules/serialization/serialization.api.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Describes hooks provided by the Serialization module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Alter the serialization 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_serialization_type_uri_alter(&$uri, $context = array()) {
+ if ($context['mymodule'] == TRUE) {
+ $base = \Drupal::config('serialization.settings')->get('link_domain');
+ $uri = str_replace($base, 'http://mymodule.domain', $uri);
+ }
+}
+
+
+/**
+ * Alter the serialization 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_serialization_relation_uri_alter(&$uri, $context = array()) {
+ if ($context['mymodule'] == TRUE) {
+ $base = \Drupal::config('serialization.settings')->get('link_domain');
+ $uri = str_replace($base, 'http://mymodule.domain', $uri);
+ }
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/core/modules/serialization/serialization.install b/core/modules/serialization/serialization.install
new file mode 100644
index 00000000000..de3004945e4
--- /dev/null
+++ b/core/modules/serialization/serialization.install
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @file
+ * Update functions for the serialization module.
+ */
+
+/**
+ * @defgroup updates-8.2.x-to-8.3.x
+ * @{
+ * Update functions from 8.2.x to 8.3.x.
+ */
+
+/**
+ * Move 'link_domain' from 'rest.settings' to 'serialization.settings'.
+ */
+function serialization_update_8301() {
+ $config_factory = \Drupal::configFactory();
+
+ // The default value for the 'link_domain' key is `~`, which is the YAML
+ // equivalent of PHP's `NULL`. If the REST module is not installed, this is
+ // the value we will store in 'serialization.settings'.
+ $link_domain = NULL;
+
+ // But if the REST module was installed, we migrate its 'link_domain' setting,
+ // because we are actually moving that setting from 'rest.settings' to
+ // 'serialization.settings'.
+ $rest_settings = $config_factory->getEditable('rest.settings');
+ if ($rest_settings->getRawData() !== []) {
+ $link_domain = $rest_settings->get('link_domain');
+ // Remove the 'link_domain' setting from 'rest.settings'.
+ $rest_settings->clear('link_domain')
+ ->save();
+ }
+
+ $serialization_settings = $config_factory->getEditable('serialization.settings');
+ $serialization_settings->set('link_domain', $link_domain);
+ $serialization_settings->save(TRUE);
+}
+
+/**
+ * @} End of "defgroup updates-8.2.x-to-8.3.x".
+ */
diff --git a/core/modules/serialization/serialization.services.yml b/core/modules/serialization/serialization.services.yml
index c8fb3767f7e..98a190bb264 100644
--- a/core/modules/serialization/serialization.services.yml
+++ b/core/modules/serialization/serialization.services.yml
@@ -89,3 +89,13 @@ services:
tags:
- { name: event_subscriber }
arguments: ['%serializer.formats%']
+ # Link managers.
+ serialization.link_manager:
+ class: Drupal\serialization\LinkManager\LinkManager
+ arguments: ['@serialization.link_manager.type', '@serialization.link_manager.relation']
+ serialization.link_manager.type:
+ class: Drupal\serialization\LinkManager\TypeLinkManager
+ arguments: ['@cache.default', '@module_handler', '@config.factory', '@request_stack', '@entity_type.bundle.info']
+ serialization.link_manager.relation:
+ class: Drupal\serialization\LinkManager\RelationLinkManager
+ arguments: ['@cache.default', '@entity.manager', '@module_handler', '@config.factory', '@request_stack']
diff --git a/core/modules/serialization/src/LinkManager/ConfigurableLinkManagerInterface.php b/core/modules/serialization/src/LinkManager/ConfigurableLinkManagerInterface.php
new file mode 100644
index 00000000000..2e866025e02
--- /dev/null
+++ b/core/modules/serialization/src/LinkManager/ConfigurableLinkManagerInterface.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Drupal\serialization\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);
+
+}
diff --git a/core/modules/serialization/src/LinkManager/LinkManager.php b/core/modules/serialization/src/LinkManager/LinkManager.php
new file mode 100644
index 00000000000..19c83e2fefb
--- /dev/null
+++ b/core/modules/serialization/src/LinkManager/LinkManager.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace Drupal\serialization\LinkManager;
+
+class LinkManager implements LinkManagerInterface {
+
+ /**
+ * The type link manager.
+ *
+ * @var \Drupal\serialization\LinkManager\TypeLinkManagerInterface
+ */
+ protected $typeLinkManager;
+
+ /**
+ * The relation link manager.
+ *
+ * @var \Drupal\serialization\LinkManager\RelationLinkManagerInterface
+ */
+ protected $relationLinkManager;
+
+ /**
+ * Constructor.
+ *
+ * @param \Drupal\serialization\LinkManager\TypeLinkManagerInterface $type_link_manager
+ * Manager for handling bundle URIs.
+ * @param \Drupal\serialization\LinkManager\RelationLinkManagerInterface $relation_link_manager
+ * Manager for handling bundle URIs.
+ */
+ public function __construct(TypeLinkManagerInterface $type_link_manager, RelationLinkManagerInterface $relation_link_manager) {
+ $this->typeLinkManager = $type_link_manager;
+ $this->relationLinkManager = $relation_link_manager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTypeUri($entity_type, $bundle, $context = array()) {
+ return $this->typeLinkManager->getTypeUri($entity_type, $bundle, $context);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTypeInternalIds($type_uri, $context = array()) {
+ return $this->typeLinkManager->getTypeInternalIds($type_uri, $context);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRelationUri($entity_type, $bundle, $field_name, $context = array()) {
+ return $this->relationLinkManager->getRelationUri($entity_type, $bundle, $field_name, $context);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ 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;
+ }
+
+}
diff --git a/core/modules/serialization/src/LinkManager/LinkManagerBase.php b/core/modules/serialization/src/LinkManager/LinkManagerBase.php
new file mode 100644
index 00000000000..0cf7e69221d
--- /dev/null
+++ b/core/modules/serialization/src/LinkManager/LinkManagerBase.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace Drupal\serialization\LinkManager;
+
+/**
+ * Defines an abstract base-class for Serialization 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('serialization.settings')->get('link_domain')) {
+ $this->linkDomain = rtrim($domain, '/');
+ }
+ else {
+ $request = $this->requestStack->getCurrentRequest();
+ $this->linkDomain = $request->getSchemeAndHttpHost() . $request->getBasePath();
+ }
+ }
+ return $this->linkDomain;
+ }
+
+}
diff --git a/core/modules/serialization/src/LinkManager/LinkManagerInterface.php b/core/modules/serialization/src/LinkManager/LinkManagerInterface.php
new file mode 100644
index 00000000000..8986d0faacd
--- /dev/null
+++ b/core/modules/serialization/src/LinkManager/LinkManagerInterface.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\serialization\LinkManager;
+
+/**
+ * Interface implemented by link managers.
+ *
+ * There are no explicit methods on the manager interface. Instead link managers
+ * broker the interactions of the different components, and therefore must
+ * implement each component interface, which is enforced by this interface
+ * extending all of the component ones.
+ *
+ * While a link manager may directly implement these interface methods with
+ * custom logic, it is expected to be more common for plugin managers to proxy
+ * the method invocations to the respective components.
+ */
+interface LinkManagerInterface extends TypeLinkManagerInterface, RelationLinkManagerInterface {
+}
diff --git a/core/modules/serialization/src/LinkManager/RelationLinkManager.php b/core/modules/serialization/src/LinkManager/RelationLinkManager.php
new file mode 100644
index 00000000000..465dda38174
--- /dev/null
+++ b/core/modules/serialization/src/LinkManager/RelationLinkManager.php
@@ -0,0 +1,144 @@
+<?php
+
+namespace Drupal\serialization\LinkManager;
+
+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\Extension\ModuleHandlerInterface;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+class RelationLinkManager extends LinkManagerBase implements RelationLinkManagerInterface {
+
+ /**
+ * @var \Drupal\Core\Cache\CacheBackendInterface;
+ */
+ protected $cache;
+
+ /**
+ * Entity manager.
+ *
+ * @var \Drupal\Core\Entity\EntityManagerInterface
+ */
+ protected $entityManager;
+
+ /**
+ * Module handler service.
+ *
+ * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ */
+ protected $moduleHandler;
+
+ /**
+ * Constructor.
+ *
+ * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+ * The cache of relation URIs and their associated Typed Data IDs.
+ * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+ * The entity manager.
+ * @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, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, RequestStack $request_stack) {
+ $this->cache = $cache;
+ $this->entityManager = $entity_manager;
+ $this->configFactory = $config_factory;
+ $this->moduleHandler = $module_handler;
+ $this->requestStack = $request_stack;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRelationUri($entity_type, $bundle, $field_name, $context = array()) {
+ // Per the interface documentation of this method, the returned URI may
+ // optionally also serve as the URL of a documentation page about this
+ // field. However, Drupal does not currently implement such a documentation
+ // page. Therefore, we return a URI assembled relative to the site's base
+ // URL, which is sufficient to uniquely identify the site's entity type +
+ // bundle + field for use in hypermedia formats, but we do not take into
+ // account unclean URLs, language prefixing, or anything else that would be
+ // required for Drupal to be able to respond with content at this URL. If a
+ // module is installed that adds such content, but requires this URL to be
+ // different (e.g., include a language prefix), then the module must also
+ // override the RelationLinkManager class/service to return the desired URL.
+ $uri = $this->getLinkDomain() . "/rest/relation/$entity_type/$bundle/$field_name";
+ $this->moduleHandler->alter('serialization_relation_uri', $uri, $context);
+ // @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This
+ // hook is invoked to maintain backwards compatibility
+ $this->moduleHandler->alter('rest_relation_uri', $uri, $context);
+ return $uri;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRelationInternalIds($relation_uri, $context = array()) {
+ $relations = $this->getRelations($context);
+ if (isset($relations[$relation_uri])) {
+ return $relations[$relation_uri];
+ }
+ return FALSE;
+ }
+
+ /**
+ * Get the array of relation links.
+ *
+ * Any field can be handled as a relation simply by changing how it is
+ * normalized. Therefore, there is no prior knowledge that can be used here
+ * to determine which fields to assign relation URIs. Instead, each field,
+ * 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($context = array()) {
+ $cid = 'serialization:links:relations';
+ $cache = $this->cache->get($cid);
+ if (!$cache) {
+ $this->writeCache($context);
+ $cache = $this->cache->get($cid);
+ }
+ return $cache->data;
+ }
+
+ /**
+ * Writes the cache of relation links.
+ *
+ * @param array $context
+ * Context from the normalizer/serializer operation.
+ */
+ 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(), $context);
+ $data[$relation_uri] = array(
+ 'entity_type' => $entity_type,
+ 'bundle' => $bundle,
+ 'field_name' => $field_definition->getName(),
+ );
+ }
+ }
+ }
+ }
+ // These URIs only change when field info changes, so cache it permanently
+ // and only clear it when the fields cache is cleared.
+ $this->cache->set('serialization:links:relations', $data, Cache::PERMANENT, array('entity_field_info'));
+ }
+
+}
diff --git a/core/modules/serialization/src/LinkManager/RelationLinkManagerInterface.php b/core/modules/serialization/src/LinkManager/RelationLinkManagerInterface.php
new file mode 100644
index 00000000000..fb0aac8f8f2
--- /dev/null
+++ b/core/modules/serialization/src/LinkManager/RelationLinkManagerInterface.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\serialization\LinkManager;
+
+interface RelationLinkManagerInterface extends ConfigurableLinkManagerInterface {
+
+ /**
+ * Gets the URI that corresponds to a field.
+ *
+ * When using hypermedia formats, this URI can be used to indicate which
+ * field the data represents. Documentation about this field can also be
+ * provided at this URI.
+ *
+ * @param string $entity_type
+ * The bundle's entity type.
+ * @param string $bundle
+ * 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, $context = array());
+
+ /**
+ * Translates a REST URI into internal IDs.
+ *
+ * @param string $relation_uri
+ * Relation URI to transform into internal IDs
+ *
+ * @return array
+ * Array with keys 'entity_type', 'bundle' and 'field_name'.
+ */
+ public function getRelationInternalIds($relation_uri);
+
+}
diff --git a/core/modules/serialization/src/LinkManager/TypeLinkManager.php b/core/modules/serialization/src/LinkManager/TypeLinkManager.php
new file mode 100644
index 00000000000..22801376716
--- /dev/null
+++ b/core/modules/serialization/src/LinkManager/TypeLinkManager.php
@@ -0,0 +1,150 @@
+<?php
+
+namespace Drupal\serialization\LinkManager;
+
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+class TypeLinkManager extends LinkManagerBase implements TypeLinkManagerInterface {
+
+ /**
+ * Injected cache backend.
+ *
+ * @var \Drupal\Core\Cache\CacheBackendInterface;
+ */
+ protected $cache;
+
+ /**
+ * Module handler service.
+ *
+ * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ */
+ protected $moduleHandler;
+
+ /**
+ * The bundle info service.
+ *
+ * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+ */
+ protected $bundleInfoService;
+
+ /**
+ * Constructor.
+ *
+ * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+ * The injected cache backend for caching type URIs.
+ * @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.
+ * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info_service
+ * The bundle info service.
+ */
+ public function __construct(CacheBackendInterface $cache, ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, RequestStack $request_stack, EntityTypeBundleInfoInterface $bundle_info_service) {
+ $this->cache = $cache;
+ $this->configFactory = $config_factory;
+ $this->moduleHandler = $module_handler;
+ $this->requestStack = $request_stack;
+ $this->bundleInfoService = $bundle_info_service;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTypeUri($entity_type, $bundle, $context = array()) {
+ // Per the interface documentation of this method, the returned URI may
+ // optionally also serve as the URL of a documentation page about this
+ // bundle. However, Drupal does not currently implement such a documentation
+ // page. Therefore, we return a URI assembled relative to the site's base
+ // URL, which is sufficient to uniquely identify the site's entity type and
+ // bundle for use in hypermedia formats, but we do not take into account
+ // unclean URLs, language prefixing, or anything else that would be required
+ // for Drupal to be able to respond with content at this URL. If a module is
+ // installed that adds such content, but requires this URL to be different
+ // (e.g., include a language prefix), then the module must also override the
+ // TypeLinkManager class/service to return the desired URL.
+ $uri = $this->getLinkDomain() . "/rest/type/$entity_type/$bundle";
+ $this->moduleHandler->alter('serialization_type_uri', $uri, $context);
+ // @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. This
+ // hook is invoked to maintain backwards compatibility
+ $this->moduleHandler->alter('rest_type_uri', $uri, $context);
+ return $uri;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTypeInternalIds($type_uri, $context = array()) {
+ $types = $this->getTypes($context);
+ if (isset($types[$type_uri])) {
+ return $types[$type_uri];
+ }
+ return FALSE;
+ }
+
+ /**
+ * 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($context = array()) {
+ $cid = 'serialization:links:types';
+ $cache = $this->cache->get($cid);
+ if (!$cache) {
+ $data = $this->writeCache($context);
+ }
+ else {
+ $data = $cache->data;
+ }
+ return $data;
+ }
+
+ /**
+ * Writes the cache 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 writeCache($context = array()) {
+ $data = array();
+
+ // Type URIs correspond to bundles. Iterate through the bundles to get the
+ // URI and data for them.
+ $entity_types = \Drupal::entityManager()->getDefinitions();
+ foreach ($this->bundleInfoService->getAllBundleInfo() as $entity_type_id => $bundles) {
+ // Only content entities are supported currently.
+ // @todo Consider supporting config entities.
+ if ($entity_types[$entity_type_id]->entityClassImplements(ConfigEntityInterface::class)) {
+ continue;
+ }
+ foreach ($bundles as $bundle => $bundle_info) {
+ // Get a type URI for the bundle.
+ $bundle_uri = $this->getTypeUri($entity_type_id, $bundle, $context);
+ $data[$bundle_uri] = array(
+ 'entity_type' => $entity_type_id,
+ 'bundle' => $bundle,
+ );
+ }
+ }
+ // These URIs only change when entity info changes, so cache it permanently
+ // and only clear it when entity_info is cleared.
+ $this->cache->set('serialization:links:types', $data, Cache::PERMANENT, array('entity_types'));
+ return $data;
+ }
+
+}
diff --git a/core/modules/serialization/src/LinkManager/TypeLinkManagerInterface.php b/core/modules/serialization/src/LinkManager/TypeLinkManagerInterface.php
new file mode 100644
index 00000000000..fed9119cf4b
--- /dev/null
+++ b/core/modules/serialization/src/LinkManager/TypeLinkManagerInterface.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Drupal\serialization\LinkManager;
+
+interface TypeLinkManagerInterface extends ConfigurableLinkManagerInterface {
+
+ /**
+ * Gets the URI that corresponds to a bundle.
+ *
+ * When using hypermedia formats, this URI can be used to indicate which
+ * bundle the data represents. Documentation about required and optional
+ * fields can also be provided at this URI.
+ *
+ * @param $entity_type
+ * 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, $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, $context = array());
+
+}
diff --git a/core/modules/serialization/tests/fixtures/update/drupal-8.rest-serialization_update_8301.php b/core/modules/serialization/tests/fixtures/update/drupal-8.rest-serialization_update_8301.php
new file mode 100644
index 00000000000..b83448b5f05
--- /dev/null
+++ b/core/modules/serialization/tests/fixtures/update/drupal-8.rest-serialization_update_8301.php
Binary files differ
diff --git a/core/modules/serialization/tests/fixtures/update/drupal-8.serialization-serialization_update_8301.php b/core/modules/serialization/tests/fixtures/update/drupal-8.serialization-serialization_update_8301.php
new file mode 100644
index 00000000000..4c41134d482
--- /dev/null
+++ b/core/modules/serialization/tests/fixtures/update/drupal-8.serialization-serialization_update_8301.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains database additions to drupal-8.bare.standard.php.gz for testing the
+ * upgrade path of serialization_update_8301().
+ */
+
+use Drupal\Core\Database\Database;
+
+$connection = Database::getConnection();
+
+// Set the schema version.
+$connection->insert('key_value')
+ ->fields([
+ 'collection' => 'system.schema',
+ 'name' => 'serialization',
+ 'value' => 'i:8000;',
+ ])
+ ->execute();
+
+// Update core.extension.
+$extensions = $connection->select('config')
+ ->fields('config', ['data'])
+ ->condition('collection', '')
+ ->condition('name', 'core.extension')
+ ->execute()
+ ->fetchField();
+$extensions = unserialize($extensions);
+$extensions['module']['serialization'] = 0;
+$connection->update('config')
+ ->fields([
+ 'data' => serialize($extensions),
+ ])
+ ->condition('collection', '')
+ ->condition('name', 'core.extension')
+ ->execute();
diff --git a/core/modules/serialization/tests/serialization_test/serialization_test.module b/core/modules/serialization/tests/serialization_test/serialization_test.module
new file mode 100644
index 00000000000..c47ca2fe87f
--- /dev/null
+++ b/core/modules/serialization/tests/serialization_test/serialization_test.module
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Contains hook implementations for testing Serialization module.
+ */
+
+/**
+ * Implements hook_serialization_type_uri_alter().
+ */
+function serialization_test_serialization_type_uri_alter(&$uri, $context = array()) {
+ if (!empty($context['serialization_test'])) {
+ $uri = 'serialization_test_type';
+ }
+}
+
+/**
+ * Implements hook_rest_relation_uri_alter().
+ */
+function serialization_test_serialization_relation_uri_alter(&$uri, $context = array()) {
+ if (!empty($context['serialization_test'])) {
+ $uri = 'serialization_test_relation';
+ }
+}
diff --git a/core/modules/serialization/tests/src/Functional/Update/CreateSerializationSettingsForLinkDomainUpdateTest.php b/core/modules/serialization/tests/src/Functional/Update/CreateSerializationSettingsForLinkDomainUpdateTest.php
new file mode 100644
index 00000000000..a6e55d47153
--- /dev/null
+++ b/core/modules/serialization/tests/src/Functional/Update/CreateSerializationSettingsForLinkDomainUpdateTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\serialization\Functional\Update;
+
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+
+/**
+ * Tests that 'serialization.settings' is created, to store 'link_domain'.
+ *
+ * @see https://www.drupal.org/node/2758897
+ *
+ * @group serialization
+ */
+class CreateSerializationSettingsForLinkDomainUpdateTest extends UpdatePathTestBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ protected static $modules = ['serialization'];
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDatabaseDumpFiles() {
+ $this->databaseDumpFiles = [
+ __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+ __DIR__ . '/../../../fixtures/update/drupal-8.serialization-serialization_update_8301.php',
+ ];
+ }
+
+ /**
+ * Tests serialization_update_8301().
+ */
+ public function testSerializationSettingsCreated() {
+ // Make sure we have the expected values before the update.
+ $serialization_settings = $this->config('serialization.settings');
+ $this->assertIdentical([], $serialization_settings->getRawData());
+
+ $this->runUpdates();
+
+ // Make sure we have the expected values after the update.
+ $serialization_settings = \Drupal::configFactory()->get('serialization.settings');
+ $this->assertTrue(array_key_exists('link_domain', $serialization_settings->getRawData()));
+ $this->assertIdentical(NULL, $serialization_settings->getRawData()['link_domain']);
+ }
+
+}
diff --git a/core/modules/serialization/tests/src/Functional/Update/MigrateLinkDomainSettingFromRestToSerializationUpdateTest.php b/core/modules/serialization/tests/src/Functional/Update/MigrateLinkDomainSettingFromRestToSerializationUpdateTest.php
new file mode 100644
index 00000000000..5e490577db8
--- /dev/null
+++ b/core/modules/serialization/tests/src/Functional/Update/MigrateLinkDomainSettingFromRestToSerializationUpdateTest.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Drupal\Tests\serialization\Functional\Update;
+
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+
+/**
+ * 'link_domain' is migrated from 'rest.settings' to 'serialization.settings'.
+ *
+ * @see https://www.drupal.org/node/2758897
+ *
+ * @group serialization
+ */
+class MigrateLinkDomainSettingFromRestToSerializationUpdateTest extends UpdatePathTestBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ protected static $modules = ['rest', 'serialization'];
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDatabaseDumpFiles() {
+ $this->databaseDumpFiles = [
+ __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
+ __DIR__ . '/../../../fixtures/update/drupal-8.serialization-serialization_update_8301.php',
+ __DIR__ . '/../../../fixtures/update/drupal-8.rest-serialization_update_8301.php',
+ ];
+ }
+
+ /**
+ * Tests serialization_update_8301().
+ */
+ public function testLinkDomainMigratedFromRestSettingsToSerializationSettings() {
+ // Make sure we have the expected values before the update.
+ $serialization_settings = $this->config('serialization.settings');
+ $this->assertIdentical([], $serialization_settings->getRawData());
+ $rest_settings = $this->config('rest.settings');
+ $this->assertTrue(array_key_exists('link_domain', $rest_settings->getRawData()));
+ $this->assertIdentical('http://example.com', $rest_settings->getRawData()['link_domain']);
+
+ $this->runUpdates();
+
+ // Make sure we have the expected values after the update.
+ $serialization_settings = \Drupal::configFactory()->get('serialization.settings');
+ $this->assertTrue(array_key_exists('link_domain', $serialization_settings->getRawData()));
+ $this->assertIdentical('http://example.com', $serialization_settings->getRawData()['link_domain']);
+ $rest_settings = $this->config('rest.settings');
+ $this->assertFalse(array_key_exists('link_domain', $rest_settings->getRawData()));
+ }
+
+}
diff --git a/core/modules/serialization/tests/src/Kernel/SerializationLinkManagerTest.php b/core/modules/serialization/tests/src/Kernel/SerializationLinkManagerTest.php
new file mode 100644
index 00000000000..e88ef0ab492
--- /dev/null
+++ b/core/modules/serialization/tests/src/Kernel/SerializationLinkManagerTest.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Drupal\Tests\serialization\Kernel;
+
+use Drupal\Core\Url;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * @coversDefaultClass \Drupal\serialization\LinkManager\LinkManager
+ * @group serialization
+ */
+class SerializationLinkManagerTest extends KernelTestBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public static $modules = ['serialization', 'serialization_test', 'rest_test', 'system'];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+ \Drupal::service('router.builder')->rebuild();
+ }
+
+ /**
+ * @covers ::getTypeUri
+ */
+ public function testGetTypeUri() {
+ /* @var \Drupal\rest\LinkManager\TypeLinkManagerInterface $type_manager */
+ $type_manager = \Drupal::service('serialization.link_manager.type');
+ $base = Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString();
+ $link = $type_manager->getTypeUri('node', 'page');
+ $this->assertSame($link, $base . 'rest/type/node/page');
+ // Now with optional context.
+ $link = $type_manager->getTypeUri('node', 'page', ['serialization_test' => TRUE]);
+ $this->assertSame($link, 'serialization_test_type');
+ // Test BC: hook_rest_type_uri_alter().
+ $link = $type_manager->getTypeUri('node', 'page', ['rest_test' => TRUE]);
+ $this->assertSame($link, 'rest_test_type');
+ }
+
+ /**
+ * @covers ::getRelationUri
+ */
+ public function testGetRelationUri() {
+ /* @var \Drupal\rest\LinkManager\RelationLinkManagerInterface $relation_manager */
+ $relation_manager = \Drupal::service('serialization.link_manager.relation');
+ $base = Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString();
+ $link = $relation_manager->getRelationUri('node', 'page', 'field_ref');
+ $this->assertSame($link, $base . 'rest/relation/node/page/field_ref');
+ // Now with optional context.
+ $link = $relation_manager->getRelationUri('node', 'page', 'foobar', ['serialization_test' => TRUE]);
+ $this->assertSame($link, 'serialization_test_relation');
+ // Test BC: hook_rest_relation_uri_alter().
+ $link = $relation_manager->getRelationUri('node', 'page', 'foobar', ['rest_test' => TRUE]);
+ $this->assertSame($link, 'rest_test_relation');
+ }
+
+ /**
+ * @covers ::setLinkDomain
+ */
+ public function testSerializationLinkManagersSetLinkDomain() {
+ /* @var \Drupal\rest\LinkManager\LinkManager $link_manager */
+ $link_manager = \Drupal::service('serialization.link_manager');
+ $link_manager->setLinkDomain('http://example.com/');
+ $link = $link_manager->getTypeUri('node', 'page');
+ $this->assertEqual($link, 'http://example.com/rest/type/node/page');
+ $link = $link_manager->getRelationUri('node', 'page', 'field_ref');
+ $this->assertEqual($link, 'http://example.com/rest/relation/node/page/field_ref');
+ }
+
+}