Problem/Motivation

At present serialization of entities with their references requires the link managers in rest module.
This means modules like hal and default_content rely on having rest module enabled, when all they really want to do is deserialize/denormalize entities with references intact.
We shouldn't need rest module enabled to be able to normalize/denormalize to and from hal_json or any other format that supports entity reference relations.

Proposed resolution

Move the following services/classes into serialization module.

rest.link_manager:
    class: Drupal\rest\LinkManager\LinkManager
    arguments: ['@rest.link_manager.type', '@rest.link_manager.relation']
  rest.link_manager.type:
    class: Drupal\rest\LinkManager\TypeLinkManager
    arguments: ['@cache.default', '@module_handler', '@config.factory', '@request_stack']
  rest.link_manager.relation:
    class: Drupal\rest\LinkManager\RelationLinkManager
    arguments: ['@cache.default', '@entity.manager', '@module_handler', '@config.factory', '@request_stack']

Leave the old classes behind, make them empty shells that extend from the ones in serialization and mark them as deprecated.

Make hal module use the serialization module version.
Make hal module no longer depend on rest module.
Write tests to verify the above is true.

Remaining tasks

Agree if this is something we want to do
Patch

User interface changes

None

API changes

None

Data model changes

None

CommentFileSizeAuthor
#51 increment.txt482 byteseffulgentsia
#51 2758897-51.patch69.94 KBeffulgentsia
#49 increment.txt790 byteseffulgentsia
#49 2758897-48.patch70.04 KBeffulgentsia
#43 interdiff-2758897-43.txt913 bytesdamiankloip
#43 2758897-43.patch70.24 KBdamiankloip
#38 interdiff-2758897-38.txt6.14 KBdamiankloip
#38 2758897-38.patch70.23 KBdamiankloip
#37 2758897-36.patch71.16 KBdamiankloip
#36 2758897-36.patch68.79 KBdamiankloip
#34 interdiff-2758897-34.txt882 bytesdamiankloip
#34 2758897-34.patch68.79 KBdamiankloip
#30 interdiff.txt7.9 KBWim Leers
#30 2758897-30.patch78.97 KBWim Leers
#28 interdiff.txt2.13 KBWim Leers
#28 2758897-28.patch71.24 KBWim Leers
#25 2758897-23.patch70.44 KBWim Leers
#23 interdiff.txt10.26 KBWim Leers
#23 2758897-23.patch68.06 KBWim Leers
#20 interdiff.txt9 KBWim Leers
#20 2758897-20.patch57.9 KBWim Leers
#19 interdiff.txt2.22 KBWim Leers
#19 2758897-19.patch48.97 KBWim Leers
#18 interdiff.txt8.71 KBWim Leers
#18 2758897-18.patch48.99 KBWim Leers
#17 interdiff.txt261 bytesWim Leers
#17 2758897-17.patch45.55 KBWim Leers
#13 2758897-13.patch45.34 KBWim Leers
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

larowlan created an issue. See original summary.

larowlan’s picture

Issue summary: View changes
dawehner’s picture

+1 for the general idea.
There was also an issue to also get rid of serialization module and move it to core instead. Serialization module was initially just there, because core was less flexible in some place.

Wim Leers’s picture

+1 for concept.

There was also an issue to also get rid of serialization module and move it to core instead. Serialization module was initially just there, because core was less flexible in some place.

Also +1.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

larowlan’s picture

Issue tags: +Default content
Wim Leers’s picture

Is this possible to do without breaking BC?

larowlan’s picture

Yep, we have to leave the old services/classes behind extending from the parent.

We did similar for BrowserTestBase, left a deprecated shell behind in simpletest module but moved the actual guts to core's Tests namespace

Wim Leers’s picture

Ok. If you can provide a patch, I'd be happy to review it.

However, how is this going to interact with #2296029: Move Serialization module back into a core/lib component? Does that mean we just move this service directly into core? In other words, this could then be a precursor for #2296029: Move Serialization module back into a core/lib component, and a much smaller one at that! :)

Grayside’s picture

Another consideration is the interaction between serialization and HTTP headers. E.g., suppose URLs derived by the existing Link managers should be used in Link headers? Should that be supported without requiring event subscribers to decode the serialized result?

This is related to the general class of behaviors that might change HTTP headers or cache tags based on processing objects.

Wim Leers’s picture

e0ipso’s picture

+1 on this.

Wim Leers’s picture

Status: Active » Needs review
Issue tags: +Needs upgrade path, +Needs upgrade path tests
FileSize
45.34 KB

Alright, let's get this going. Here's an initial patch.

Still TODO:

  1. we'll also need to migrate the link_domain setting from rest.settings to serialization.settings. This is an upgrade path. And it will need tests. (See \Drupal\serialization\LinkManager\LinkManagerBase::getLinkDomain().)
  2. Figure out what to do about the mention of "REST" in \Drupal\serialization\LinkManager\RelationLinkManager::getRelationUri()
  3. Figure out what to do about the mention of "REST" in \Drupal\serialization\LinkManager\TypeLinkManager::getTypeUri()

But before spending time on that, I wanted a +1 on this approach so far.

Wim Leers’s picture

This blocks #2829746: Clean up \Drupal\jsonapi\LinkManager\LinkManager(Interface), which is currently contrib, but we're working on moving the JSON API module into core (see #2757967: API-first initiative). So tagging blocker.

larowlan’s picture

Oh man, I totally worked on this during a plane ride from QLD to NSW, but forgot to upload it.
Good thing is we have essentially the same code.

In terms of 2 and 3 I'd replace 'REST' module with 'Drupal'

Thanks Wim, looking good.

e0ipso’s picture

This also looks good to me. Thanks Wim!

Wim Leers’s picture

FileSize
45.55 KB
261 bytes

#15 + #16: thanks for the swift reviews! :)

#15: Oh :( Well, great to see both of our work validated then :) Thanks for the suggestion for points 2 + 3.

This addresses #13.2 and #13.3. It also ensures BC for hook_rest_(type|relation)_uri_alter().

Wim Leers’s picture

FileSize
48.99 KB
8.71 KB

Ugh. I only added a new file in #17. Here's the rest of the intended changes.

Wim Leers’s picture

FileSize
48.97 KB
2.22 KB

In #18, I also updated the default type/relation URIs from $this->getLinkDomain() . "/rest/…" to $this->getLinkDomain() . "/serialization/…". This breaks BC. So, reverting that change.

(#18 should also fail, because RestLinkManagerTest will catch this change. #2737719: EntityResource: Provide comprehensive test coverage: for every entity type, every format, every method would also detect this BC break. We really need #2737719: EntityResource: Provide comprehensive test coverage: for every entity type, every format, every method to land.)

Wim Leers’s picture

FileSize
57.9 KB
9 KB

So #18 made it so that the invocation of hook_rest_(type|relation)_uri_alter() hooks happens in the link manager classes that have been moved to the serialization module. In other words:
these hooks are now renamed to hook_serialization_(type|relation)_uri_alter()
but the old hooks are also still called, to ensure BC

What I had not yet done, was updating \Drupal\Tests\rest\Kernel\RestLinkManagerTest. It uses the rest_test module, which contains the rest_test_rest_type_uri_alter() and rest_test_rest_relation_uri_alter() hook implementations. Those should be moved to the serialization_test module. And the implementations in the rest_test module should be kept to test BC.

Wim Leers’s picture

Some context for the changes in #20.

  1. +++ b/core/modules/serialization/tests/src/Kernel/SerializationLinkManagerTest.php
    @@ -0,0 +1,74 @@
    +  public static $modules = ['serialization', 'serialization_test', 'rest_test', 'system'];
    

    Note this is no longer installing the rest module. No more dependence on rest, yay!

    Note that we still have rest_test there, but solely for testing BC of those alter hooks.

  2. +++ b/core/modules/serialization/tests/src/Kernel/SerializationLinkManagerTest.php
    @@ -0,0 +1,74 @@
    +    // 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');
    

    The last two lines used to be originally in the place of those first two lines. Now the primary test must of course be the hook_serialization_* alter hooks. So we test that first, and then assert that BC works.

The last submitted patch, 18: 2758897-18.patch, failed testing.

Wim Leers’s picture

Issue tags: -Needs upgrade path, -Needs upgrade path tests
FileSize
68.06 KB
10.26 KB

Aaand upgrade path plus tests. There is explicit test coverage for both possible cases:

  1. serialization module is installed, rest module is NOT installed: test coverage ensures serialization.settings is created and contains link_domain: ~.
  2. serialization and rest modules are both installed: test coverage ensures serialization.settings is created, with a link_domain value that is migrated from rest.settings, and link_domain is deleted from rest.settings

Status: Needs review » Needs work

The last submitted patch, 23: 2758897-23.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
70.44 KB
error: cannot apply binary patch to 'core/modules/serialization/tests/fixtures/update/drupal-8.rest-serialization_update_8301.php' without full index line
error: core/modules/serialization/tests/fixtures/update/drupal-8.rest-serialization_update_8301.php: patch does not apply
Patch Failed to apply

git + binary patches (or files with serialized PHP, which are strings, which git insists on interpreting as binary) == pain

Identical patch, but this time with --binary.

Wim Leers’s picture

Title: Consider moving rest link manager services into serialization module » Move rest module's "link manager" services to serialization module

Yay! The upgrade path tests passed :)

This is now ready for final review. Just reading the interdiffs since #13 is sufficient!

larowlan’s picture

+++ b/core/modules/serialization/serialization.api.php
@@ -0,0 +1,62 @@
+    $base = \Drupal::config('rest.settings')->get('link_domain');
...
+    $base = \Drupal::config('rest.settings')->get('link_domain');

Is rest.settings the correct example?

  1. +++ b/core/modules/serialization/tests/fixtures/update/drupal-8.serialization-serialization_update_8301.php
    @@ -0,0 +1,37 @@
    +    'value' => 'i:8000;',
    

    should we use serialize(8000) here so its explicit what the format is? Depends what we do elsewhere I guess.

  2. +++ b/core/modules/serialization/tests/src/Functional/Update/CreateSerializationSettingsForLinkDomainUpdateTest.php
    @@ -0,0 +1,47 @@
    + * @see https://www.drupal.org/node/2758897
    

    Do we normally reference issues like this?

Wim Leers’s picture

FileSize
71.24 KB
2.13 KB

RE: rest.settings: HAH! Great catch :) Fixed.

  1. Yeah, we do this same thing elsewhere.
  2. Well, we also do it in \Drupal\rest\Tests\Update\EntityResourcePermissionsUpdateTest and \Drupal\rest\Tests\Update\ResourceGranularityUpdateTest.
Wim Leers’s picture

Change record created: https://www.drupal.org/node/2830467.

Wim Leers’s picture

FileSize
78.97 KB
7.9 KB

From the IS:

Leave the old classes behind, make them empty shells that extend from the ones in serialization and mark them as deprecated.

This is what #28 does.

Make hal module use the serialization module version.
Make hal module no longer depend on rest module.

We don't do this yet! So, doing that now.
Perhaps this belongs in a separate issue. But I'll leave that up to the committer to decide. If we want to do it separately, we'll just need to revert this interdiff :)

Status: Needs review » Needs work

The last submitted patch, 30: 2758897-30.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Needs review
fail: [PHP Fatal error] Line 13 of core/modules/serialization/src/LinkManager/TypeLinkManager.php:
 Interface 'Drupal\rest\LinkManager\TypeLinkManagerInterface' not found

Hm…

It seems this is failing because of:

namespace Drupal\serialization\LinkManager;

use Drupal\rest\LinkManager\TypeLinkManagerInterface as BcTypeLinkManagerInterface;

class TypeLinkManager extends LinkManagerBase implements TypeLinkManagerInterface, BcTypeLinkManagerInterface {

i.e. the serialization module does not depend on the rest module, so it seems it's possible that the using of the old interface to guarantee BC doesn't actually work. Presumably the autoloader doesn't allow REST module's classes to be accessed when the REST module is not installed.

It just happens to be that #30 exposes that flaw.

Is that theory correct? If so, I don't know what the best way to fix this would be, without breaking BC. IOW, what @larowlan proposed in #8 would appear to be impossible:

Yep, we have to leave the old services/classes behind extending from the parent.

We did similar for BrowserTestBase, left a deprecated shell behind in simpletest module but moved the actual guts to core's Tests namespace

Moving things to lib/Drupal/Core is possible, because that's guaranteed to be always present. In the case of this issue/patch, we're moving it to the rest module, which is not guaranteed to be present.

So, do we want to move the link manager to lib/Drupal/Core instead (like I already proposed in #9)? That'd partially solve #2296029: Move Serialization module back into a core/lib component too. But then what about the link_domain setting? That could then no longer live in serialization.settings.

Moving to NR for feedback.

larowlan’s picture

in my head it worked the other way around, the rest ones extended from serialization, looking at my patch that was the approach I was taking too.

damiankloip’s picture

Here is a reroll to start with. Plus interdiff with the main significant change conflict.

Status: Needs review » Needs work

The last submitted patch, 34: 2758897-34.patch, failed testing.

damiankloip’s picture

Status: Needs work » Needs review
FileSize
68.79 KB

Let's try again.

damiankloip’s picture

damiankloip’s picture

So, can we do this instead? Agree we cannot have rest classes/interfaces being depended on in serialization module. This seems like the only real solution?

damiankloip’s picture

+++ b/core/modules/rest/rest.services.yml
@@ -11,18 +11,22 @@ services:
-  #   serialization.link_manager.type instead.
+  #   serialization.link_manager instead.
...
-  #   serialization.link_manager.relation instead.
+  #   serialization.link_manager instead.

Yes, I failed at copying these comments properly.

The last submitted patch, 36: 2758897-36.patch, failed testing.

The last submitted patch, 37: 2758897-36.patch, failed testing.

Wim Leers’s picture

Status: Needs review » Needs work

#38 passes. #30 fails. So clearly @damiankloip's approach is feasible (#38), mine is not (#30).

#38 summarizes his approach like this:

So, can we do this instead? Agree we cannot have rest classes/interfaces being depended on in serialization module. This seems like the only real solution?

Effectively, this means:

  1. +++ b/core/modules/serialization/src/LinkManager/LinkManager.php
    @@ -2,9 +2,7 @@
    -use Drupal\rest\LinkManager\LinkManagerInterface as BcLinkManagerInterface;
    -
    -class LinkManager implements LinkManagerInterface, BcLinkManagerInterface {
    +class LinkManager implements LinkManagerInterface {
    

    LinkManager was moved from rest to serialization, but it continued to implement the LinkManagerInterface from rest.

    This did not work for the reasons given in #32.

    Same for the RelationLinkManager and TypeLinkManager classes.

  2. +++ b/core/modules/rest/src/LinkManager/LinkManager.php
    @@ -8,4 +8,4 @@
    -class LinkManager extends MovedLinkManager {}
    +class LinkManager extends MovedLinkManager implements LinkManagerInterface {}
    

    Consequently, the thin LinkManager class that was created in rest just to avoid breaking code is now itself responsible for implementing the corresponding original interface (the one in rest). That's what's being changed here.

  3. +++ b/core/modules/rest/rest.services.yml
    @@ -11,18 +11,22 @@ services:
       rest.link_manager:
    -    alias: serialization.link_manager
    +    parent: serialization.link_manager
    +    class: Drupal\rest\LinkManager\LinkManager
    

    And as a final consequence, the rest.link_manager service can no longer point to the serialization.link_manager service, because it must continue to implement the interface defined in the rest module to not break BC. So it must not be an alias to another service, but instead it must point to the class highlighted in the previous point.

AFAICT this is solid. RTBC.

Thanks, @damiankloip!


Just marking NW instead of RTBC for the nits that @damiankloip already pointed out himself in #39, then this is RTBC.

damiankloip’s picture

Status: Needs work » Needs review
FileSize
70.24 KB
913 bytes

Thanks, Wim! Thanks for the comprehensive write up. That seems 100% accurate :) We keep the REST services (as they extend the serialization ones now, but change the class only), and implement the original interfaces in the original classes only.

Wim Leers’s picture

Priority: Normal » Major
Status: Needs review » Reviewed & tested by the community
Issue tags: +Contributed project blocker

Whew! So glad to see this being ready :)

Also, bumping this to major, since it living in the rest module causes other modules to have to reimplement this. Without this being fixed, certain contrib modules can't move forward (see original report by @larowlan, plus the JSON API module, which has had to introduce its own link manager).

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 43: 2758897-43.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Reviewed & tested by the community

HEAD broke due to a broken Outside-In commit. This is still RTBC.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

effulgentsia’s picture

Version: 8.4.x-dev » 8.3.x-dev
effulgentsia’s picture

+++ b/core/modules/serialization/src/LinkManager/LinkManagerBase.php
@@ -44,6 +44,7 @@ public function setLinkDomain($domain) {
+      // @todo move this to serialization.settings, and provide an upgrade path.
       if ($domain = $this->configFactory->get('rest.settings')->get('link_domain')) {

This is the only @todo in this patch, and the upgrade path is already in the patch, so we should fix which config file we get this from, especially since the issue summary is about not requiring rest.module to be enabled. This patch does that.

effulgentsia’s picture

Ticking credit boxes.

effulgentsia’s picture

Removed unused use statements.

  • effulgentsia committed bfaf6b6 on 8.4.x
    Issue #2758897 by Wim Leers, damiankloip, larowlan: Move rest module's "...

  • effulgentsia committed 39b8c5d on 8.3.x
    Issue #2758897 by Wim Leers, damiankloip, larowlan: Move rest module's "...
effulgentsia’s picture

Status: Reviewed & tested by the community » Fixed

Pushed to 8.4.x and cherry picked to 8.3.x.

Normally, the change in #49 would be something I would want another person to review, but because we're only a few hours from the alpha1 code freeze, I took the liberty of committing #51 without that review. I hope it's ok.

However, related to that change:

+++ b/core/modules/serialization/tests/src/Kernel/SerializationLinkManagerTest.php
@@ -0,0 +1,74 @@
+  public static $modules = ['serialization', 'serialization_test', 'rest_test', 'system'];
...
+  public function testSerializationLinkManagersSetLinkDomain() {

A follow-up issue to improve this test to not enable rest.module (implicitly via rest_test) would be great.

Wim Leers’s picture

Oops, #49 was indeed an oversight. Thanks!

A follow-up issue to improve this test to not enable rest.module (implicitly via rest_test) would be great.

Done, includes RTBC patch: #2848933: SerializationLinkManagerTest should not enable the rest_test module (because it implicitly enables the rest module).

Wim Leers’s picture

Wim Leers’s picture

And hah, we apparently already fixed #2473749: Remove rest as a dependency of hal as part of this patch! :)

Berdir’s picture

This broke tests in entity_reference_revisions and possibly other modules as well.

https://www.drupal.org/pift-ci-job/589215

Was confused for a moment because the service still exists, but we were relying on the fact that hal depends on rest.module and didn't explicitly enable that in the test. The runtime code also only implicitly checks for rest, FileEntityServiceProvider (ERR has the same check without the comment):

    // Check for installed REST & HAL modules, as HAL requires REST.
    if (isset($modules['hal']) ) {

Not sure if changing module dependencies is an API change or not? :)

Wim Leers’s picture

Was confused for a moment because the service still exists, but we were relying on the fact that hal depends on rest.module and didn't explicitly enable that in the test.

Glad to hear it's just that :)

The hal module depending on rest was always a flaw, as #2473749: Remove rest as a dependency of hal explained. Never rely on implicit module dependencies. Fortunately, it's an easy fix on your end — and for anybody else who may be using this :)

Added this to the CR. And also published the CR — apparently @effulgentsia forgot to publish it :)

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

Wim Leers’s picture