Problem/Motivation

Menu link content entities when normalized contain references to node serial IDs (nid) and not UUIDs, this means they cannot be deployed.
Snippet:

...
  ],
    "link": [
        {
            "uri": "entity:node\/2",
            "title": null,
            "options": []
        }
    ],
...

Proposed resolution

Add new normalizers to menu_link_content.module for when hal and serialization modules are enabled to handle normalizing MenuLinkContent entities.

The normalizer should include the entity UUID in the normalized output and then use that to lookup the entity when denormalizing, ensuring that the link references the right entity.

Note this works alongside #2353611: Make it possible to link to an entity by UUID - as allowing links to entities via UUIDs is useful in body text and other methods of linking, not just for menu links.

Also related is #2315773: Create a menu link field type/widget/formatter which seeks to make the relationship between an entity and it's menu link a first-class entity reference, however that may need to wait until D9 because of API breaks.

Remaining tasks

None

User interface changes

None

API changes

None

Data model changes

None

CommentFileSizeAuthor
#154 interdiff-2577923-152-154.txt1.63 KBmohit_aghera
#154 2577923-154.patch9.21 KBmohit_aghera
#152 interdiff_150-152.txt5.09 KBpradhumanjain2311
#152 2577923-152.patch8.97 KBpradhumanjain2311
#150 2577923-150.patch5.09 KBpradhumanjain2311
#145 interdiff-2577923-141-145.txt655 bytesmohit_aghera
#145 2577923-145.patch9.26 KBmohit_aghera
#143 interdiff-2577923-135-144.txt4.65 KBmohit_aghera
#143 2577923-141.patch8.62 KBmohit_aghera
#135 interdiff_132-135.txt2.57 KBridhimaabrol24
#135 2577923-135.patch8.53 KBridhimaabrol24
#132 2577923-132.patch5.9 KBnarendra.rajwar27
#132 interdiff_128-132.txt1.75 KBnarendra.rajwar27
#129 interdiff_125_128.txt841 bytespookmish
#129 2577923-128.patch5.64 KBpookmish
#127 interdiff_119-125.txt822 bytesjohnwebdev
#127 2577923-125.patch5.55 KBjohnwebdev
#119 Screen Shot 2017-11-09 at 19.10.37.png70.29 KBWim Leers
#119 Screen Shot 2017-11-09 at 19.09.59.png17.32 KBWim Leers
#119 2577923-119.patch4.78 KBWim Leers
#115 2577923-115.patch30.9 KBtedbow
#115 interdiff-109-115.txt2.23 KBtedbow
#109 interdiff-105-109.txt2.24 KBAComben
#109 2577923-109.patch30.87 KBAComben
#105 interdiff.txt1.86 KBtedbow
#105 2577923-105.patch30.91 KBtedbow
#103 interdiff.txt2.06 KBtedbow
#103 2577923-103.patch30.93 KBtedbow
#95 2577923-95.patch30.97 KBtedbow
#95 interdiff-91-95.txt798 bytestedbow
#91 2577923-91.patch31 KBtedbow
#91 interdiff-89-91.txt1.19 KBtedbow
#89 2577923-89.patch30.65 KBtedbow
#89 interdiff-87-89.txt9.04 KBtedbow
#87 2577923-87.patch30.4 KBtedbow
#87 interdiff-85-87.txt12.07 KBtedbow
#85 interdiff--82-85.txt5.34 KBtedbow
#85 2577923-85-menu_deploy.patch27.89 KBtedbow
#82 2577923-82.patch27.98 KBtedbow
#82 interdiff-77-82.txt6.79 KBtedbow
#77 2577923-77.patch28.38 KBtedbow
#71 interdiff-69-71.txt17.55 KBtedbow
#71 2577923-71.patch37.84 KBtedbow
#69 interdiff-66-69.txt6.45 KBtedbow
#69 2577923-69.patch29.83 KBtedbow
#66 interdiff-2577923-63-66.txt3.24 KBtedbow
#66 2577923-66.patch27.39 KBtedbow
#63 2577923-54.patch26.43 KBlarowlan
#61 interdiff-2577923-54-61.txt5.39 KBtedbow
#61 2577923-61.patch26.23 KBtedbow
#57 interdiff-2577923-54-56.txt0 bytestedbow
#57 2577923-57.patch23.6 KBtedbow
#54 interdiff-2577923-49-54.txt2.9 KBtedbow
#54 2577923-54.patch26.43 KBtedbow
#49 2577923-menu-link-deploy.29.patch26.45 KBlarowlan
#49 interdiff.txt5.76 KBlarowlan
#49 tshirt.jpeg39.94 KBlarowlan
#46 2577923-menu-link-deploy.46.patch26.54 KBlarowlan
#46 interdiff.txt1.24 KBlarowlan
#42 2577923-menu-link-deploy.42.patch26.56 KBlarowlan
#42 interdiff.txt1.12 KBlarowlan
#40 2577923-menu-link-deploy.40.patch26.55 KBlarowlan
#40 interdiff.txt2.6 KBlarowlan
#29 2577923-menu-link-deploy.29.patch26.65 KBlarowlan
#29 interdiff.txt1.13 KBlarowlan
#27 2577923-menu-link-deploy.27.patch26.65 KBlarowlan
#27 interdiff.txt23.43 KBlarowlan
#21 2577923-menu-link-deploy.21.patch17.54 KBlarowlan
#18 2577923-menu-link-deploy.18.patch17.64 KBlarowlan
#18 interdiff.txt8.04 KBlarowlan
#16 2577923-menu-link-deploy.16.patch17.36 KBlarowlan
#16 interdiff.txt15.01 KBlarowlan
#10 2577923-menu-link-deploy.10.patch11.4 KBlarowlan
#10 interdiff.txt675 byteslarowlan
#8 2577923-menu-link-deploy.8.patch11.39 KBlarowlan
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

larowlan created an issue. See original summary.

larowlan’s picture

Personally I think option 2 (UUID) is the 'best we can do now' and option 3 is the 'what's the quickest way to fix this'

timmillwood’s picture

Personally I think getting this fixed before RC1 is going to be hard, so we should push the quickest way for now, and even if we do or don't get it in 8.0.0 we work on the "best" way for 8.1.0.

klausi’s picture

Option 3 sounds like the most feasible approach right now. We should add a uuid property in the JSON that contains the node/entity UUID. I would not mess with the uri property since that would be an API change if it suddenly contains UUIDs. On denormailze() we can lookup the ID from the UUID and replace it.

Crell’s picture

Issue summary: View changes

Well, we're past RC now. :-) My concern with option 3 is that only fixes the problem when going through the serializer. Is that the only place this problem manifests? Are you certain?

larowlan’s picture

FYI Option 3 is implemented in EntityPilot in #2694909: Custom menu links have incorrect node ID and there is also another implementation for Default Content in #2670954: Add Better Normalizers as a dependency

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.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

Title: [meta] Menu link content entities that point to nodes are not deployable » Menu link content entities that point to nodes are not deployable
Version: 8.1.x-dev » 8.2.x-dev
Status: Active » Needs review
FileSize
11.39 KB

Adds a new normalizer and tests a.k.a option 3.
We still need option 2 as well, for links in node-bodies etc (but not just for menu link content entities).

Mostly borrowed from Entity Pilot with the addition of embedding parent menu_link_content entities.

Status: Needs review » Needs work

The last submitted patch, 8: 2577923-menu-link-deploy.8.patch, failed testing.

larowlan’s picture

Status: Needs work » Needs review
FileSize
675 bytes
11.4 KB

Fixed namespace

benjy’s picture

Few minor points below

  1. +++ b/core/modules/menu_link_content/src/MenuLinkContentServiceProvider.php
    @@ -0,0 +1,34 @@
    +        new Reference('entity.manager'),
    

    Do we want to use the now deprecated entity manager or inject entity_type and entity.repository.

  2. +++ b/core/modules/menu_link_content/src/Normalizer/MenuLinkContentNormalizer.php
    @@ -0,0 +1,144 @@
    +          if ($target_entity = $this->entityManager->getStorage($target_entity_type_id)->load($target_entity_id)) {
    ...
    +          // Entity-type not found.
    +          continue;
    

    Could we use $manager->hasHandler('storage') here? Might read a little clearer than try/catch

dawehner’s picture

I'm wondering why this is specific to hal serialization. The same problem should existing in JSON and XML etc. as well?

+++ b/core/modules/menu_link_content/src/Normalizer/MenuLinkContentNormalizer.php
@@ -0,0 +1,144 @@
+        try {
+          if ($target_entity = $this->entityManager->getStorage($target_entity_type_id)->load($target_entity_id)) {
+            $normalized = $this->embedEntity($entity, $format, $context, $target_entity, $normalized, self::PSUEDO_FIELD_NAME);
+            $normalized['link'][$key] += [
+              'target_uuid' => $target_entity->uuid(),
+            ];
+          }
+        }
+        catch (PluginNotFoundException $e) {
+          // Entity-type not found.
+          continue;
+        }

If this is the only case we could check with an if whether the entity type exists already. Do you prefer one style over the other?

timmillwood’s picture

Status: Needs review » Needs work

Added this issue as a use case in #2690747: [PLAN] Create an index of UUIDs.

Also, switching this to needs work, the main thing I noticed in the patch was the use of EntityManger which is not deprecated, as noted in #11.

larowlan’s picture

Category: Task » Bug report
Issue tags: +needs backport to 8.1.x

I'd class this as a bug

larowlan’s picture

Assigned: Unassigned » larowlan

Do we want to use the now deprecated entity manager or inject entity_type and entity.repository

I'm following the parent class signature. Deviating from that will add future refactoring work.

Could we use $manager->hasHandler('storage') here? Might read a little clearer than try/catch

Agree, will fix

I'm wondering why this is specific to hal serialization. The same problem should existing in JSON and XML etc. as well?

Sure, I don't think we do embedding in serialization module, just adding the target_uuid, so I'll do that there too.

Working on this.

larowlan’s picture

Status: Needs work » Needs review
FileSize
15.01 KB
17.36 KB

Fixes #11 and #12

jibran’s picture

Looks good to me just minor issues.

  1. +++ b/core/modules/menu_link_content/src/MenuLinkContentServiceProvider.php
    @@ -0,0 +1,44 @@
    +      $service_definition = new Definition('Drupal\menu_link_content\Normalizer\HalMenuLinkContentNormalizer', [
    ...
    +      $service_definition = new Definition('Drupal\menu_link_content\Normalizer\MenuLinkContentNormalizer', [
    
    +++ b/core/modules/menu_link_content/src/Normalizer/HalMenuLinkContentNormalizer.php
    @@ -0,0 +1,140 @@
    +  protected $supportedInterfaceOrClass = 'Drupal\menu_link_content\MenuLinkContentInterface';
    
    +++ b/core/modules/menu_link_content/src/Normalizer/MenuLinkContentNormalizer.php
    @@ -0,0 +1,70 @@
    +  protected $supportedInterfaceOrClass = 'Drupal\menu_link_content\MenuLinkContentInterface';
    

    We can use ::class here.

  2. +++ b/core/modules/menu_link_content/src/Normalizer/HalMenuLinkContentNormalizer.php
    @@ -0,0 +1,140 @@
    +        $scheme = parse_url($link['uri'], PHP_URL_SCHEME);
    ...
    +        $path = parse_url($link['uri'], PHP_URL_PATH);
    ...
    +        $scheme = parse_url($link['uri'], PHP_URL_SCHEME);
    ...
    +        $path = parse_url($link['uri'], PHP_URL_PATH);
    
    +++ b/core/modules/menu_link_content/src/Normalizer/MenuLinkContentNormalizer.php
    @@ -0,0 +1,70 @@
    +        $scheme = parse_url($link['uri'], PHP_URL_SCHEME);
    ...
    +        $path = parse_url($link['uri'], PHP_URL_PATH);
    

    We should combine these calls. Store the return value in an array.

  3. +++ b/core/modules/menu_link_content/src/Normalizer/HalMenuLinkContentNormalizer.php
    @@ -0,0 +1,140 @@
    +        if (strpos($parent['value'], PluginBase::DERIVATIVE_SEPARATOR) !== FALSE) {
    

    Can we please add a comment here explaining this?

larowlan’s picture

jibran’s picture

Status: Needs review » Reviewed & tested by the community

Seems ready to me.

dawehner’s picture

Status: Reviewed & tested by the community » Needs review

Nice test coverage!

  1. +++ b/core/modules/menu_link_content/src/MenuLinkContentServiceProvider.php
    @@ -0,0 +1,46 @@
    +    if (isset($modules['hal'])) {
    +      // Add a hal normalizer service for menu-link-content entities.
    +      $service_definition = new Definition(HalMenuLinkContentNormalizer::class, [
    +        new Reference('rest.link_manager'),
    +        new Reference('entity.manager'),
    +        new Reference('module_handler'),
    +      ]);
    +      // The priority must be higher than that of
    +      // serializer.normalizer.entity.hal in hal.services.yml.
    +      $service_definition->addTag('normalizer', array('priority' => 40));
    +      $container->setDefinition('menu_link_content.normalizer.menu_link_content.hal', $service_definition);
    +    }
    +    elseif (isset($modules['serialization'])) {
    +      // Add a generic normalizer service for menu-link-content entities.
    +      $service_definition = new Definition(MenuLinkContentNormalizer::class, [
    +        new Reference('entity.manager'),
    +      ]);
    +      // The priority must be higher than that of
    +      // serializer.normalizer.content_entity in serialization.services.yml.
    +      $service_definition->addTag('normalizer', array('priority' => 10));
    ...
    +    }
    

    Don't we want both, you might want to support HAL and another format

  2. +++ b/core/modules/menu_link_content/src/Normalizer/MenuLinkContentNormalizer.php
    @@ -0,0 +1,70 @@
    +/**
    + * @file
    + * Contains Drupal\menu_link_content\Normalizer\MenuLinkContentNormalizer.
    + */
    

    Let's not add it

larowlan’s picture

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Nice work!

amateescu’s picture

Menu link content entities when normalized contain references to node serial IDs (nid) and not UUIDs, this means they cannot be deployed.

Isn't this a problem for every entity type that uses a link field? Why are fixing only menu_link_content here instead of fixing the link field directly?

dawehner’s picture

Good point!

larowlan’s picture

Yeah true, although I think anywhere else we're sensible enough to use an ER field :)

#1911080: Replace menu node form additions with entity reference field

larowlan’s picture

Rerolling against LinkItem

larowlan’s picture

Status: Reviewed & tested by the community » Needs review
Related issues: +#2698785: Cannot deploy book nodes - book metatdata not serialized
FileSize
23.43 KB
26.65 KB

Something like this.

Kept the tests as is, but moved the link elements into link module.

Added an EntityReferenceEmbeddingTrait to move the common bits into a trait shared with EntityReferenceItem, will help with #2698785: Cannot deploy book nodes - book metatdata not serialized too.

Not surprisingly, interdiff almost as big as patch :)

Status: Needs review » Needs work

The last submitted patch, 27: 2577923-menu-link-deploy.27.patch, failed testing.

larowlan’s picture

Status: Needs work » Needs review
FileSize
1.13 KB
26.65 KB

Missed a hunk.

Status: Needs review » Needs work

The last submitted patch, 29: 2577923-menu-link-deploy.29.patch, failed testing.

larowlan’s picture

Random fail

jibran’s picture

+++ b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
@@ -12,6 +12,8 @@
 class EntityReferenceItemNormalizer extends FieldItemNormalizer implements UuidReferenceInterface {

@larowlan do these changes affect DER?

larowlan’s picture

Will check

jibran’s picture

Status: Needs work » Reviewed & tested by the community

I completely agree with #23. This makes much more sense now.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 29: 2577923-menu-link-deploy.29.patch, failed testing.

larowlan’s picture

Status: Needs work » Reviewed & tested by the community

Retesting, random Migrate fail

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs issue summary update

The issue summary could do with an update as it is not clear what the changes are and also whether we should do this or #2353611: Make it possible to link to an entity by UUID - or do both.

larowlan’s picture

Issue summary: View changes
Status: Needs work » Reviewed & tested by the community
Issue tags: -Needs issue summary update

Updated issue summary, back to RTBC

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Some tiny tiny nits but because i don't know what to change the test comment too setting to needs work. @larowlan please rtbc once fixed.

+++ b/core/modules/menu_link_content/tests/src/Kernel/Normalizer/HalMenuLinkContentNormalizerTest.php
@@ -0,0 +1,100 @@
+  /**
+   * Tests prepare passengers event.
+   */

+++ b/core/modules/menu_link_content/tests/src/Kernel/Normalizer/MenuLinkContentNormalizerTest.php
@@ -0,0 +1,85 @@
+  /**
+   * Tests prepare passengers event.
+   */

What event is this?

diff --git a/core/modules/hal/src/Normalizer/EntityReferenceEmbeddingTrait.php b/core/modules/hal/src/Normalizer/EntityReferenceEmbeddingTrait.php
index b8d6507..2424f43 100644
--- a/core/modules/hal/src/Normalizer/EntityReferenceEmbeddingTrait.php
+++ b/core/modules/hal/src/Normalizer/EntityReferenceEmbeddingTrait.php
@@ -1,8 +1,4 @@
 <?php
-/**
- * @file
- * Contains Drupal\hal\Normalizer\EntityReferenceEmbeddingTrait.
- */
 
 namespace Drupal\hal\Normalizer;
 
diff --git a/core/modules/menu_link_content/src/Normalizer/HalMenuLinkContentNormalizer.php b/core/modules/menu_link_content/src/Normalizer/HalMenuLinkContentNormalizer.php
index f9db016..ed66761 100644
--- a/core/modules/menu_link_content/src/Normalizer/HalMenuLinkContentNormalizer.php
+++ b/core/modules/menu_link_content/src/Normalizer/HalMenuLinkContentNormalizer.php
@@ -4,7 +4,6 @@
 
 use Drupal\Component\Plugin\PluginBase;
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\hal\Normalizer\ContentEntityNormalizer;
 use Drupal\hal\Normalizer\EntityReferenceEmbeddingTrait;
 use Drupal\menu_link_content\MenuLinkContentInterface;

Some coding standards that need fixing.

larowlan’s picture

What event is this?

copy/paste fail from Entity pilot module, where a lot of this code originated.

Fixed

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/link/src/LinkServiceProvider.php
    @@ -0,0 +1,46 @@
    + */
    +class LinkServiceProvider implements ServiceModifierInterface {
    ...
    +  public function alter(ContainerBuilder $container) {
    

    Does this need to be an alter? I think we're adding services here. I guess we're copying \Drupal\menu_link_content\MenuLinkContentServiceProvider but I'm not sure this is right. Do we need to do this for the container.modules param?

  2. +++ b/core/modules/link/src/LinkServiceProvider.php
    @@ -0,0 +1,46 @@
    +      $container->setDefinition('serializer.normalizer.link_item.hal', $service_definition);
    ...
    +      $container->setDefinition('serializer.normalizer.link_item', $service_definition);
    

    These services should be called 'link.SOMETHING' because they are provided by the link module.

larowlan’s picture

Status: Needs work » Needs review
FileSize
1.12 KB
26.56 KB

1 - Fixed
2 - That's not consistent with other serializers registered by e.g. hal module - happy to change it - but wanted to make sure we had consensus on preferred approach - currently core prefixes all serializers service IDs with serializer

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

larowlan’s picture

discussed on irc with @alexpott conclusion was we need to have a pattern that all a module's services start with module.

larowlan’s picture

FileSize
1.24 KB
26.54 KB

Fixes #45 I think this is ready to go back to RTBC

jibran’s picture

Version: 8.3.x-dev » 8.1.x-dev
Assigned: larowlan » Unassigned
Status: Needs review » Reviewed & tested by the community

It is a bug so it can be committed to 8.1.x. RTBC as #45 and #41 are addressed.

alexpott’s picture

Version: 8.1.x-dev » 8.3.x-dev
Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs change record
  1. +++ b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
    @@ -12,6 +12,8 @@
    +  use EntityReferenceEmbeddingTrait;
    +
    

    This is not a change allowed in a patch release. And the beta is closed by now so I honestly think this is only eligible for 8.3.x

  2. +++ b/core/modules/menu_link_content/src/Normalizer/HalMenuLinkContentNormalizer.php
    @@ -0,0 +1,51 @@
    +  /**
    +   * Psuedo field name for embedding parent target entity.
    +   *
    +   * @var string
    +   */
    +  const PSUEDO_PARENT_FIELD_NAME = 'menu_link_content_parent_entity';
    

    PSEUDO no?

  3. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,115 @@
    +        list($target_entity_type_id, $target_entity_id) = explode('/', $path);
    ...
    +      list($target_entity_type_id, $target_entity_id) = explode('/', $path);
    

    No point declaring $target_entity_id

  4. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,115 @@
    +      if (isset($link['target_uuid'])) {
    

    This can be checked in the first if in the this method. Less indentation...

  5. +++ b/core/modules/menu_link_content/src/Normalizer/MenuLinkContentNormalizer.php
    @@ -0,0 +1,41 @@
    +        if (isset($link['target_uuid'])) {
    

    This can be checked earlier to do less in the foreach.

larowlan’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
39.94 KB
5.76 KB
26.45 KB

This is not a change allowed in a patch release. And the beta is closed by now so I honestly think this is only eligible for 8.3.x

- can you elaborate more. I'm not disagreeing, just want to understand what about that change isn't allowed - if you could point me to some docs, that'd be great - I truly have no idea what is and isn't allowed and whether we backport or forward port.

2 - gah, I was wearing this t-shirt and I still got it wrong?
mmm stylish
3-5 fixed.

larowlan’s picture

Issue tags: -Needs change record
Wim Leers’s picture

Wim Leers’s picture

Status: Needs review » Needs work

AFAICT #49 addressed #48's feedback. I agree with #49.1 though, I also don't fully understand why that change is problematic. It's fully BC. However, I think that the mere introduction of a new trait is not acceptable. Although I'm not sure how that is a helpful rule in this case. Alex, can you confirm that?

I'd RTBC, but have further feedback myself:

  1. The main critical question: doesn't this mean that the link a menu link points to becomes somewhat meaningless, because target_uuid can "override" it? Wouldn't it be better to just land #2353611: Make it possible to link to an entity by UUID, ensure that provides an upgrade path for all existing menu link content entities, and then this problem would also be solved?
  2. +++ b/core/modules/hal/src/Normalizer/EntityReferenceEmbeddingTrait.php
    @@ -0,0 +1,66 @@
    +   *   Entity being reference.
    

    Nit: s/reference/referenced/

  3. +++ b/core/modules/hal/src/Normalizer/EntityReferenceEmbeddingTrait.php
    @@ -0,0 +1,66 @@
    +   *   Rest link manager service.
    

    Nit: s/Rest/REST/

  4. +++ b/core/modules/hal/src/Normalizer/EntityReferenceEmbeddingTrait.php
    @@ -0,0 +1,66 @@
    +    return array(
    

    Nit: Why not use [] notation for this new trait?

  5. +++ b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
    --- /dev/null
    +++ b/core/modules/link/src/LinkServiceProvider.php
    
    +++ b/core/modules/link/src/LinkServiceProvider.php
    @@ -0,0 +1,46 @@
    +    if (isset($modules['hal'])) {
    +      // Add a hal normalizer service for LinkItem fields.
    ...
    +    if (isset($modules['serialization'])) {
    

    Hm this is kind of … painful. Can't this just live in hal module and link module, respectively? Without the conditionality?

  6. +++ b/core/modules/menu_link_content/src/MenuLinkContentServiceProvider.php
    @@ -0,0 +1,46 @@
    +    if (isset($modules['hal'])) {
    ...
    +    if (isset($modules['serialization'])) {
    

    Same concerns here.

  7. +++ b/core/modules/menu_link_content/tests/src/Kernel/Normalizer/MenuLinkContentNormalizerTest.php
    @@ -0,0 +1,85 @@
    +    $normalized = $serializer->normalize($link, 'xml');
    ...
    +    $denormalized = $serializer->denormalize($normalized, MenuLinkContent::class, 'json');
    

    Nit: should be consistent, both 'json'?

larowlan’s picture

Issue tags: +Default content
tedbow’s picture

Status: Needs work » Needs review
FileSize
26.43 KB
2.9 KB

Addressing @Wim Leers' review in #52

2,3,4,7 Fixed nits

5,6 Won't the hal and serialization ServiceProviders modules get complicated if they have a to register every other modules' normalization services. Also won't those ServiceProviders classes have their own if clauses because they would need to check if Link module is enabled. For instance for this
$service_definition = new Definition(HalLinkItemNormalizer::class, [

1, @larowlan you would be better to answer the question about #2353611: Make it possible to link to an entity by UUID

larowlan’s picture

In regards to #52.1 yes that would solve the issue *if* the default was to use the UUID version of the link. However, it is not - the serial ID will remain the default link representation (canonical).

The two issue are complimentary, and there is no harm (in my opinion) in having the additional context of the target_uuid in the normalized representation.

Wim Leers’s picture

Status: Needs review » Needs work
Issue tags: -needs backport to 8.1.x

#54.6: You're right, I'm not sure what I was thinking. What I meant to say: can't we unconditionally define those, which means we can just define them in link.services.yml and in menu_link_content.services.yml. The services won't be instantiated if no REST is used, and hence would also never cause errors. They're just available for discovery/use.


#55: Can you then add that justification at least to the IS, and preferably also in some sensible location in the patch? So that our future selves won't get confused by this. The test coverage seems a prime location for this. i.e. doesn't this mean that the link a menu link points to becomes somewhat meaningless, because target_uuid can "override" it? + the serial ID will remain the default link representation (canonical). + other relevant information.


Since no more 8.1.x releases are happening, this won't be backported to 8.1.x anymore. Removing issue tag.

tedbow’s picture

Status: Needs work » Needs review
FileSize
23.6 KB
0 bytes

RE #54.6:
Moved services out of ServiceProvider Classes and in to *.services.yml files.

Status: Needs review » Needs work

The last submitted patch, 57: 2577923-57.patch, failed testing.

larowlan’s picture

+++ b/core/modules/link/link.services.yml
@@ -0,0 +1,11 @@
+    arguments: ['@entity_type.manager', '@rest.link_manager', '@entity.repository']

rest.link_manager doesn't exist unless rest module is enabled, which is why this was in a service provider :)

Wim Leers’s picture

So there we go, that's what we want to document on this service provider then! :)

tedbow’s picture

Status: Needs work » Needs review
FileSize
26.23 KB
5.39 KB

Ok doing my interdiff against #54 because that is what started from.

1. So we need a service provider for 2 of the services. But for 1 of the services in each module we can use *.services.yml so I used those.
re

So there we go, that's what we want to document on this service provider then! :)

Added a comment in each ServiceProvider
2. also re @alexpott's comment in #41 about LinkServiceProvider implements ServiceModifierInterface

Does this need to be an alter? I think we're adding services here. I guess we're copying \Drupal\menu_link_content\MenuLinkContentServiceProvider but I'm not sure this is right. Do we need to do this for the container.modules param?

LinkServiceProvider was changed to use ServiceProviderInterface but it is not clear why MenuLinkContentServiceProvider is using ServiceModifierInterface in the first placeand not ServiceProviderInterface. Since MenuLinkContentServiceProvider is new in this patch it seems it should also use ServiceProviderInterface.

So changed that. Maybe someone will point out something I missed.

Status: Needs review » Needs work

The last submitted patch, 61: 2577923-61.patch, failed testing.

larowlan’s picture

Status: Needs work » Needs review
FileSize
26.43 KB

Let's leave it at #54, there are parent classes that we extend from that don't exist without those modules.

jibran’s picture

Status: Needs review » Reviewed & tested by the community

It is ready imo.

Wim Leers’s picture

Status: Reviewed & tested by the community » Needs work

AFAICT this was never addressed:

#55: Can you then add that justification at least to the IS, and preferably also in some sensible location in the patch? So that our future selves won't get confused by this. The test coverage seems a prime location for this. i.e. doesn't this mean that the link a menu link points to becomes somewhat meaningless, because target_uuid can "override" it? + the serial ID will remain the default link representation (canonical). + other relevant information.

Please think about out future selves.

tedbow’s picture

Status: Needs work » Needs review
FileSize
27.39 KB
3.24 KB

Please think about out future selves.

Pausing to think of our future selves...

Ok here is a patch that adds comments about the the process and how ids are used for canonical links but recreated on denormalization based on UUID.

dawehner’s picture

  1. +++ b/core/modules/link/src/LinkServiceProvider.php
    @@ -0,0 +1,46 @@
    +  public function register(ContainerBuilder $container) {
    ...
    +    if (isset($modules['hal'])) {
    ...
    +    if (isset($modules['serialization'])) {
    

    ubernitpick. I would have started with $modules['serialization'] and then use 'hal', giving that the serialization is the more generic module than the hal one.

  2. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,112 @@
    +class HalLinkItemNormalizer extends FieldItemNormalizer {
    
    +++ b/core/modules/link/src/Normalizer/LinkItemNormalizer.php
    @@ -0,0 +1,59 @@
    +class LinkItemNormalizer extends ComplexDataNormalizer {
    

    Is there a reason the link/generic implementation doesn't support denormalize()? Maybe we should document this here

  3. +++ b/core/modules/menu_link_content/src/MenuLinkContentServiceProvider.php
    @@ -0,0 +1,46 @@
    +  public function alter(ContainerBuilder $container) {
    ...
    +    if (isset($modules['hal'])) {
    ...
    +    if (isset($modules['serialization'])) {
    

    Same thing as above.

  4. +++ b/core/modules/menu_link_content/tests/src/Kernel/Normalizer/HalMenuLinkContentNormalizerTest.php
    @@ -0,0 +1,100 @@
    +
    +namespace Drupal\Tests\menu_link_content\Kernel\Normalizer;
    +
    
    +++ b/core/modules/menu_link_content/tests/src/Kernel/Normalizer/MenuLinkContentNormalizerTest.php
    @@ -0,0 +1,90 @@
    +
    +namespace Drupal\Tests\menu_link_content\Kernel\Normalizer;
    +
    

    One more thing: I'd expected to see a test in link and hal module as well.

Wim Leers’s picture

Status: Needs review » Needs work

#65: Thanks! Nits for that interdiff:

+++ b/core/modules/link/src/Normalizer/LinkItemNormalizer.php
@@ -46,6 +46,10 @@ public function normalize($object, $format = NULL, array $context = array()) {
+        // create the correct 'uri' for the entity even when the entity id has

+++ b/core/modules/menu_link_content/src/Normalizer/MenuLinkContentNormalizer.php
@@ -7,6 +7,12 @@
+ * on demoralization the 'uri' of the link will be updated to use the current id
...
+ * entities they will link to the correct entities even if the entity ids have

+++ b/core/modules/menu_link_content/tests/src/Kernel/Normalizer/MenuLinkContentNormalizerTest.php
@@ -71,10 +71,15 @@ public function testMenuLinkNormalizer() {
+    // entity's id has changed such as in a deployment.
...
+    // the same node. The canonical links for entities use the entity id but the
...
+    // entity id.

Nit: s/id/ID/


#66: Thanks for the review, @dawehner! Glad that you're also taking a look at this :)

tedbow’s picture

Status: Needs work » Needs review
FileSize
29.83 KB
6.45 KB

@dawehner and @Wim Leers thanks for reviews!

#67
1,3 fixed.

2.

Is there a reason the link/generic implementation doesn't support denormalize()? Maybe we should document this here

@dawehner good question!
I think supporting denormalize() is a mistake it means that deploy denormalization benefit will only work for MenuLinkContent entities not other fieldable entities that have Link fields.

This patch adds a test for this which should fail currently. I will now work on patch that added denormalize().

Status: Needs review » Needs work

The last submitted patch, 69: 2577923-69.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review
FileSize
37.84 KB
17.55 KB

Ok here is patch that should the test introduced in #69 working. Hopefully it does break to many other ;)

I found the problem:

  1. \Drupal\serialization\Normalizer\ContentEntityNormalizer didn't override denormalize
  2. \Drupal\serialization\Normalizer\EntityNormalizer::denormalize was simply creating the entity like $entity = $this->entityManager->getStorage($entity_type_id)->create($data);
  3. For this reason no denomarlizers on FieldItem Normalizers were being called.
  4. I had to introduced \Drupal\serialization\Normalizer\FieldNormalizer and \Drupal\serialization\Normalizer\FieldItemNormalizer which are very close copies of the HAL versions of these normalizers.
  5. All of the above allowed deleting MenuLinkContentNormalizer because the MenuLinkContent entity no longer needs a denormalizer as this can be done on the field item level.
  6. \Drupal\menu_link_content\Normalizer\HalMenuLinkContentNormalizer is still necessary because it needs to handle 'parent' which a string but references the plugin id of the menu item so it can be handled generically.

Some questions/thoughts

  1. I would image that all the changes related to serialization should really be done in separate issue against the serialization module, something like Support denomorlization on fielditem normlizers
  2. Is all the above really necessary are other entities going to use the link field with the "entity" scheme. If add configurable link field to an entity now and point to /node/1 the scheme is internal not "entity". This also true as far as I can tell if you make a regular menu item. It only uses "entity" scheme when added on the node form.
  3. Are their other fields where having a denormalizer would be useful.

Status: Needs review » Needs work

The last submitted patch, 71: 2577923-71.patch, failed testing.

tedbow’s picture

Not surprised there were bunch of test failures. Before I look into fixing them.

Anybody have feedback on whether this is useful change or should we revert back to approach of #66?

Wim Leers’s picture

  1. +++ b/core/core.services.yml
    @@ -1345,7 +1345,7 @@ services:
    -    arguments: ['@module_handler', '@cache.discovery', '@language_manager', '@cache_tags.invalidator', '@renderer']
    +    arguments: ['@module_handler', '@cache.default', '@language_manager', '@cache_tags.invalidator', '@renderer']
    

    This is from #2824548: Move token info cache to data cache bin. Should be removed from this patch.

  2. +++ b/core/modules/link/src/LinkServiceProvider.php
    @@ -27,7 +27,7 @@ public function register(ContainerBuilder $container) {
    -      $service_definition->addTag('normalizer', array('priority' => 10));
    +      $service_definition->addTag('normalizer', array('priority' => 30));
    

    Let's document why this needs priority 30.

  3. +++ b/core/modules/serialization/serialization.services.yml
    @@ -74,3 +74,11 @@ services:
    +        - { name: normalizer, priority: 11 }
    ...
    +      - { name: normalizer, priority: 11 }
    

    Let's document the rationale behind these priorities.

  4. +++ b/core/modules/serialization/src/Normalizer/ContentEntityNormalizer.php
    @@ -32,4 +32,26 @@ public function normalize($object, $format = NULL, array $context = array()) {
    +  public function denormalize($data, $class, $format = NULL, array $context = []) {
    
    +++ b/core/modules/serialization/src/Normalizer/FieldItemNormalizer.php
    @@ -0,0 +1,93 @@
    +class FieldItemNormalizer extends ComplexDataNormalizer implements DenormalizerInterface {
    
    +++ b/core/modules/serialization/src/Normalizer/FieldNormalizer.php
    @@ -0,0 +1,101 @@
    +class FieldNormalizer extends NormalizerBase implements DenormalizerInterface {
    

    What I don't understand yet is how this then used to work until now?

  5. +++ b/core/modules/serialization/src/Normalizer/FieldNormalizer.php
    index fc85050..d06ae66 100644
    --- a/core/modules/views/tests/src/Kernel/Plugin/ViewsBlockTest.php
    

    This is also from an unrelated issue.

tedbow’s picture

Title: Menu link content entities that point to nodes are not deployable » [pp-1] Menu link content entities that point to nodes are not deployable
Status: Needs work » Postponed
Related issues: +#2827218: Denormalization on field items is never called: add FieldNormalizer + FieldItemNormalizer with denormalize() methods

@Wim Leers thanks for review

I create #2827218: Denormalization on field items is never called: add FieldNormalizer + FieldItemNormalizer with denormalize() methods to solve the FieldItem denormalization problem first

Postponing this 1 on that

Wim Leers’s picture

Title: [pp-1] Menu link content entities that point to nodes are not deployable » Menu link content entities that point to nodes are not deployable
Status: Postponed » Needs work
tedbow’s picture

Status: Needs work » Needs review
FileSize
28.38 KB

Ok then is just a re-roll of #71 without the serialization module changes as they were committed as part of #2827218: Denormalization on field items is never called: add FieldNormalizer + FieldItemNormalizer with denormalize() methods. Yay!!!

I tested the 3 tests this patch provides locally and they passed but presumably other tests will fail. Let's see.

Some @Wim Leers' review #74 no longer applies. The comments about documenting the priorities probably do will need to see what they will be. Might have to change the current ones and re-read this issue for numbers used so far.

jibran’s picture

Issue tags: +DER issue
Wim Leers’s picture

Version: 8.3.x-dev » 8.2.x-dev
Issue tags: -needs backport to 8.2.x

#2827218: Denormalization on field items is never called: add FieldNormalizer + FieldItemNormalizer with denormalize() methods was committed to 8.3.x only, which makes it pretty difficult to backport this. If we need to backport this, then we shouldn't have the Needs backport ot 8.2.x tag, but we should just mark this against 8.2.x-dev.

EDIT: forgot to say, in #2827218-62: Denormalization on field items is never called: add FieldNormalizer + FieldItemNormalizer with denormalize() methods, I changed that issue from "Fixed" in 8.3.x to "RTBC" in 8.2.x. The patch applies cleanly. Fingers crossed.

damiankloip’s picture

This looks really tidy in general. A couple of smalls:

  1. +++ b/core/modules/hal/src/Normalizer/EntityReferenceEmbeddingTrait.php
    @@ -0,0 +1,66 @@
    +   * @param \Symfony\Component\Serializer\Normalizer\NormalizerInterface $normalizer
    +   *   Normalizer service.
    

    This parameter should be called $serializer. This makes it a bit more confusing IMO. Yes, the serializer class is a hot mess of interfaces :)

    Could also consider just assuming that the serializer and linkManager as available as properties on classes where this trait is used? So you just use $this->serializer->normalize() instead? It makes the function signature more manageable, but does hide those dependencies a little.

  2. +++ b/core/modules/link/src/LinkServiceProvider.php
    @@ -0,0 +1,47 @@
    +      // Add a generic normalizer service for LinkItem fields.
    

    This doesn't seem like a generic normalizer, just for LinkItems?

  3. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,112 @@
    +  protected $supportedInterfaceOrClass = LinkItem::class;
    

    nit: Can you move this to the top instead (below the trait usage). Makes it easier to scan.

Wim Leers’s picture

Status: Needs review » Needs work

NW for #80.

tedbow’s picture

Status: Needs work » Needs review
FileSize
6.79 KB
27.98 KB

Ok here is fix for 3 points in #80

Status: Needs review » Needs work

The last submitted patch, 82: 2577923-82.patch, failed testing.

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

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should 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.

tedbow’s picture

Status: Needs work » Needs review
FileSize
27.89 KB
5.34 KB

Ok #82 had a bunch of test failures for 8.2.x but since comment #84 this won't get committed to 8.2.x anyways.

All the failures from #82 on 8.3.x seem to be because we are using the deprecated REST link manager. #2758897: Move rest module's "link manager" services to serialization module
Since in \Drupal\link\LinkServiceProvider we only check if Hal is enabled not Rest(no longer a dependency) this causes a error.

Changing to use new serialization.link_manager service. This also lets us get rid of any use of "rest" in this module including tests!

Wim Leers’s picture

Status: Needs review » Needs work

Changing to use new serialization.link_manager service. This also lets us get rid of any use of "rest" in this module including tests!

Hurray! :D


Looking back at the last dozen comments, it seems my review in #74 was never addressed. #77 said some of it no longer applies, and that's true. Only point 2 needs to be addressed still!


#74 also replied to the 3 questions at the end of #71.

  1. The first question there is no longer relevant; this patch no longer makes any changes to the serialization module.
  2. The second question I answered in #74.
  3. The third question I answered in #74.

None of these need extra work.


Finally, another re-review now that we have a green patch again:

  1. +++ b/core/modules/hal/src/Normalizer/EntityReferenceEmbeddingTrait.php
    @@ -0,0 +1,60 @@
    +trait EntityReferenceEmbeddingTrait {
    

    We moved logic from HAL's EntityReferenceItemNormalizer here, to this trait, so it can be reused by HAL's HalLinkItemNormalizer.

  2. +++ b/core/modules/hal/src/Normalizer/EntityReferenceEmbeddingTrait.php
    @@ -0,0 +1,60 @@
    +   * Embeds an entity into normalized data.
    

    s/normalized data/a normalization/

  3. +++ b/core/modules/link/src/LinkServiceProvider.php
    @@ -0,0 +1,47 @@
    +      $service_definition->addTag('normalizer', array('priority' => 30));
    

    s/array()/[]/

  4. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,112 @@
    +class HalLinkItemNormalizer extends FieldItemNormalizer {
    

    Why not just call this LinkItemNormalizer? The class it extends also does not have a Hal prefix.

  5. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,112 @@
    +   * Constructs a new LinkItemNormalizer object.
    

    This ironically already does not have the prefix :)

  6. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,112 @@
    +    /** @var \Drupal\link\Plugin\Field\FieldType\LinkItem $field_item */
    +    $field_name = $field_item->getParent()->getName();
    +    $entity = $field_item->getEntity();
    +    $normalized = parent::normalize($field_item, $format, $context);
    

    Let's move the parent::normalize() call to the very top. Because it doesn't require any of the variables created before it's called.

    Also, I think $normalization would be a better name than $normalized.

  7. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,112 @@
    +        $url = parse_url($link['uri']);
    +        if (!isset($url['scheme']) || $url['scheme'] !== 'entity') {
    +          continue;
    +        }
    

    This means we're skipping any URI that is not using the entity: scheme.

    It'd be much clearer if we then moved all of the logic that comes after this to a helper method.

    Then the function body would be much clearer:

    function normalize() {
      $normalization = parent::normalize(…);
    
      $field_name = …;
      if (isset($normalization[$field_name]) {
        foreach ($field as $item) {
          $uri = $item->something();
          if ($uri_uses_entity_scheme) {
            $this->decorateWithTargetUuid(…);
          }
        }
      }
    }
    

    i.e. exactly like #2825812: ImageItem should have an "derivatives" computed property, to expose all image style URLs is doing.

    We should also update the docs of LinkItemNormalizer, because just like ImageItmeNormalizer in #2825812, this is just decorating an existing normalizer, to deal with the special extra capabilities of this field type!

  8. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,112 @@
    +            $normalized[$field_name][$delta]['target_uuid'] = $target_entity->uuid();
    ...
    +      if ($entity = $this->entityRepository->loadEntityByUuid($target_entity_type_id, $link['target_uuid'])) {
    +        $link['uri'] = 'entity:' . $target_entity_type_id . '/' . $entity->id();
    +      }
    
    +++ b/core/modules/link/src/Normalizer/LinkItemNormalizer.php
    @@ -0,0 +1,88 @@
    +        $link['target_uuid'] = $target_entity->uuid();
    ...
    +      if ($entity = $this->entityRepository->loadEntityByUuid($target_entity_type_id, $data['target_uuid'])) {
    +        $data['uri'] = 'entity:' . $target_entity_type_id . '/' . $entity->id();
    +      }
    

    All of this logic is also hugely repetitive. Just like #2825812: ImageItem should have an "derivatives" computed property, to expose all image style URLs has ImageItemNormalizerTrait, used by both serialization and hal modules, we need an LinkItemNormalizerTrait here.

  9. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,112 @@
    +    $url = parse_url($link['uri']);
    +    if (isset($url['scheme']) && $url['scheme'] === 'entity' && isset($link['target_uuid'])) {
    
    +++ b/core/modules/link/src/Normalizer/LinkItemNormalizer.php
    @@ -0,0 +1,88 @@
    +    $url = parse_url($link['uri']);
    +    if (!isset($url['scheme']) || $url['scheme'] !== 'entity') {
    ...
    +      $url = parse_url($data['uri']);
    +      if (!isset($url['scheme']) || $url['scheme'] !== 'entity') {
    

    This is the second (and third and fourth) time we have URI scheme parsing logic. This indicates we need a protected static function uriUsesEntityScheme() helper method, that we call everywhere.

tedbow’s picture

Status: Needs work » Needs review
FileSize
12.07 KB
30.4 KB

@Wim Leers thanks again for the review
#74.2 updated comment about priority

re #86
1. not sure if this needs action or just a comment. HalLinkItemNormalizer is currently using EntityReferenceEmbeddingTrait
2. fixed
3. fixed both array() usages in this file
4(and 5). This class is in the namespace "Drupal\link\Normalizer" which already has a LinkItemNormalizer. The normalizers provided directly by the Hal module don't use the 'Hal' prefix but when other modules provide normalizers they have to differentiate between the 2 normalizers they provide.
#2825812: ImageItem should have an "derivatives" computed property, to expose all image style URLs has the same pattern. But in that patch we chose ImageItemHalNormalizer with "Hal" not as a prefix but before "Normalizer". We should probably use the same pattern in both issues. Either ThingHalNormalizer or HalThingNormalizer

I think I prefer ThingHalNormalizer but not changing now to get feedback.

6. fixed
7. Add the method decorateWithTargetUuid and update the class comment on both normalizers.
8. wow, I actually did this before I got to this comment when fixing above :) I called it EntityLinkItemNormalizerTrait because it all the methods deal with links that are to entities.
9. I had added this to trait above. I used the name isEntityLink will change to uriUsesEntityScheme.
Also added getTargetEntity(), getEntityPathParts(), and updateEntityUri() to this trait.

Wim Leers’s picture

Status: Needs review » Needs work
  1. Sorry for not being more clear: this was solely an observation! :)
  1. Thanks for pointing that out. Wrote #2825812-64: ImageItem should have an "derivatives" computed property, to expose all image style URLs to fix that there too. Let's drop the Hal mention from the classname altogether, all other HAL normalizers also don't have that! Ah but damn, I realized why this is not possible:

    Ah, damn, #64 does not make sense, because we have ImageItemNormalizer for serialization (i.e. default normalizer) and ImageItemHalNormalizer for hal, and both live in the same directory and namespace. That's why #64 is not feasible.


Interdiff review:

  1. +++ b/core/modules/link/src/Normalizer/EntityLinkItemNormalizerTrait.php
    @@ -0,0 +1,72 @@
    +   * @param array $link
    +   *   The link info.
    ...
    +   * @param array $link
    +   *   The link info.
    ...
    +   * @param array $link
    +   *   The link info.
    

    Hm, wouldn't $link_normalization and The link normalization. not make more sense?

  2. +++ b/core/modules/link/src/Normalizer/EntityLinkItemNormalizerTrait.php
    @@ -0,0 +1,72 @@
    +   *   The linked if available or NULL.
    

    s/linked/linked entity/
    s/available/any/

  3. +++ b/core/modules/link/src/Normalizer/EntityLinkItemNormalizerTrait.php
    @@ -0,0 +1,72 @@
    +   *   First item is entity type. The second item is entity id.
    

    s/id/ID/

  4. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -12,11 +12,21 @@
    + * the ids of the entities may have changed.
    

    s/ids/IDs/

  5. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -63,50 +73,57 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Lin
    -    $url = parse_url($link['uri']);
    -    if (isset($url['scheme']) && $url['scheme'] === 'entity' && isset($link['target_uuid'])) {
    -      $path = isset($url['path']) ? $url['path'] : '';
    -      list($target_entity_type_id,) = explode('/', $path);
    -      if ($entity = $this->entityRepository->loadEntityByUuid($target_entity_type_id, $link['target_uuid'])) {
    -        $link['uri'] = 'entity:' . $target_entity_type_id . '/' . $entity->id();
    -      }
    -    }
    +    $this->updateEntityUri($link);
    
    +++ b/core/modules/link/src/Normalizer/LinkItemNormalizer.php
    @@ -71,17 +75,7 @@ public function normalize($object, $format = NULL, array $context = array()) {
    -    if (isset($data['target_uuid'])) {
    -      $url = parse_url($data['uri']);
    -      if (!isset($url['scheme']) || $url['scheme'] !== 'entity') {
    -        return $data;
    -      }
    -      $path = isset($url['path']) ? $url['path'] : '';
    -      list($target_entity_type_id,) = explode('/', $path);
    -      if ($entity = $this->entityRepository->loadEntityByUuid($target_entity_type_id, $data['target_uuid'])) {
    -        $data['uri'] = 'entity:' . $target_entity_type_id . '/' . $entity->id();
    -      }
    -    }
    +    $this->updateEntityUri($data);
    

    So much better! (Also the other places where the trait is used.) Reuse of methods and much easier to understand code. Wins all around :)


Full patch review:

  1. +++ b/core/modules/link/src/Normalizer/EntityLinkItemNormalizerTrait.php
    @@ -0,0 +1,72 @@
    +trait EntityLinkItemNormalizerTrait {
    

    Let's mark this @internal.

  2. +++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
    @@ -0,0 +1,129 @@
    +  public function normalize($field_item, $format = NULL, array $context = array()) {
    ...
    +  public function denormalize($link, $class, $format = NULL, array $context = array()) {
    
    +++ b/core/modules/link/src/Normalizer/LinkItemNormalizer.php
    @@ -0,0 +1,82 @@
    +  public function normalize($object, $format = NULL, array $context = array()) {
    
    +++ b/core/modules/menu_link_content/src/MenuLinkContentServiceProvider.php
    @@ -0,0 +1,36 @@
    +      $service_definition->addTag('normalizer', array('priority' => 40));
    
    +++ b/core/modules/menu_link_content/src/Normalizer/HalMenuLinkContentNormalizer.php
    @@ -0,0 +1,51 @@
    +  public function normalize($entity, $format = NULL, array $context = array()) {
    

    s/array()/[]/

  3. +++ b/core/modules/menu_link_content/src/MenuLinkContentServiceProvider.php
    @@ -0,0 +1,36 @@
    +    if (isset($modules['hal'])) {
    +      // Add a hal normalizer service for menu-link-content entities.
    +      $service_definition = new Definition(HalMenuLinkContentNormalizer::class, [
    
    +++ b/core/modules/menu_link_content/src/Normalizer/HalMenuLinkContentNormalizer.php
    @@ -0,0 +1,51 @@
    +/**
    + * A normalizer to handle menu-link content links to entities.
    + */
    +class HalMenuLinkContentNormalizer extends ContentEntityNormalizer {
    

    Why only for hal and not also for serialization?


This is getting very close now :)

tedbow’s picture

Status: Needs work » Needs review
FileSize
9.04 KB
30.65 KB

#88
Interdiff review
1. fixed @param name and comment
2. fixed
3. fixed with 3 other occurrences
4. fixed with 2 other occurrences
5 Yes!

Full patch review
1. added
2. fixed
3. see #71 5,6

All of the above allowed deleting MenuLinkContentNormalizer because the MenuLinkContent entity no longer needs a denormalizer as this can be done on the field item level.

\Drupal\menu_link_content\Normalizer\HalMenuLinkContentNormalizer is still necessary because it needs to handle 'parent' which a string but references the plugin id of the menu item so it can be handled generically.

Basically in Hal we normalize parent in menu item.

This is getting very close now :)

Yay!

Wim Leers’s picture

+++ b/core/modules/link/src/Normalizer/HalLinkItemNormalizer.php
@@ -0,0 +1,129 @@
+class HalLinkItemNormalizer extends FieldItemNormalizer {

Can we add the explanation for why this normalizer exists only for hal and not for normalization (i.e. #71.5 and #71.6)?

Otherwise somebody else will surely wonder about that in the future. (I know I will!)

Other than that, this is RTBC now :)

tedbow’s picture

Added comment for our future selves.

Also fix 1 misspelling in a comment.

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community
larowlan’s picture

Looks great, a couple of defensive suggestions, feel free to ignore

  1. +++ b/core/modules/link/src/Normalizer/EntityLinkItemNormalizerTrait.php
    @@ -0,0 +1,74 @@
    +    $url = parse_url($link_normalization['uri']);
    

    we could use the second argument to parse_url here, nominating we just want the path

  2. +++ b/core/modules/link/src/Normalizer/EntityLinkItemNormalizerTrait.php
    @@ -0,0 +1,74 @@
    +    return explode('/', $path);
    

    we should use the third argument to explode here, nominating we expect 2 parts

Wim Leers’s picture

Status: Reviewed & tested by the community » Needs work

Great suggestions, thanks :)

tedbow’s picture

@larowlan thanks for the suggestions.

Added

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 95: 2577923-95.patch, failed testing.

andypost’s picture

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 95: 2577923-95.patch, failed testing.

tedbow’s picture

Status: Needs work » Reviewed & tested by the community

CI Flux again

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 95: 2577923-95.patch, failed testing.

tedbow’s picture

Assigned: Unassigned » tedbow
tedbow’s picture

Status: Needs work » Needs review
FileSize
30.93 KB
2.06 KB

Changed to use link manager in Hal module

Status: Needs review » Needs work

The last submitted patch, 103: 2577923-103.patch, failed testing.

tedbow’s picture

Status: Needs work » Needs review
FileSize
30.91 KB
1.86 KB

Whoops missed another reference to the old link manager.

Wim Leers’s picture

Title: Menu link content entities that point to nodes are not deployable » [PP-1] Menu link content entities that point to nodes are not deployable
Status: Needs review » Postponed
+++ b/core/modules/menu_link_content/tests/src/Kernel/Normalizer/HalMenuLinkContentNormalizerTest.php
@@ -0,0 +1,99 @@
+    $mock_field_uri = $link_manager->getRelationUri('menu_link_content', 'menu_link_content', 'link_target', []);
+    $parent_field_uri = $link_manager->getRelationUri('menu_link_content', 'menu_link_content', HalMenuLinkContentNormalizer::PSEUDO_PARENT_FIELD_NAME, []);
+    $node_url = $node->toUrl('canonical', ['absolute' => TRUE])->setRouteParameter('_format', 'hal_json')->toString();
+    $parent_url = $parent->toUrl('canonical', ['absolute' => TRUE])->setRouteParameter('_format', 'hal_json')->toString();
+    $context['included_fields'] = ['uuid'];
+    $embedded = $serializer->normalize($node, 'hal_json', $context);
+    $embedded_parent = $serializer->normalize($parent, 'hal_json', $context);
+    $normalized = $serializer->normalize($link, 'hal_json');
+    $this->assertEquals($node->uuid(), $normalized['link'][0]['target_uuid']);
+    $this->assertEquals([$embedded], $normalized['_embedded'][$mock_field_uri]);
+    $this->assertEquals([['href' => $node_url]], $normalized['_links'][$mock_field_uri]);
+    $this->assertEquals([$embedded_parent], $normalized['_embedded'][$parent_field_uri]);
+    $this->assertEquals([['href' => $parent_url]], $normalized['_links'][$parent_field_uri]);
+    $this->assertEquals('menu_link_content:' . $parent->uuid(), $normalized['parent'][0]['value']);

+++ b/core/modules/menu_link_content/tests/src/Kernel/Normalizer/MenuLinkContentNormalizerTest.php
@@ -0,0 +1,89 @@
+    $serializer = $this->container->get('serializer');
+    $normalized = $serializer->normalize($link, 'json');
+    // On normalization the 'target_uuid' of the entity will added so that
+    // correct URI can be created for the entity regardless of whether the
+    // entity's id has changed such as in a deployment.
+    $this->assertEquals($node->uuid(), $normalized['link'][0]['target_uuid']);

I wanted to re-RTBC this issue.

But then I realized that what these things are testing… is what should be tested in a \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase test, really.

Maybe it makes sense to keep these tests. But we definitely should have functional test coverage.

In fact, we have that test coverage being added in #2832859: Write EntityResourceTestBase subclasses for: MenuLinkContent!

Once that lands, we can just modify MenuLinkContentResourceTestBase::createEntity() to point to a node instead, and to have a parent link. Then we can repeat exactly this there, and we'll have a far better idea what these normalizations actually look like.

Wim Leers’s picture

Title: [PP-1] Menu link content entities that point to nodes are not deployable » Menu link content entities that point to nodes are not deployable
Status: Postponed » Needs review

#2832859: Write EntityResourceTestBase subclasses for: MenuLinkContent landed. Let's retest #105. If it still passes, it's RTBC.

Wim Leers’s picture

Status: Needs review » Needs work

Eh, #107 is wrong. Because, quoting myself from the bottom of #106:

Once that lands, we can just modify MenuLinkContentResourceTestBase::createEntity() to point to a node instead, and to have a parent link. Then we can repeat exactly this there, and we'll have a far better idea what these normalizations actually look like.

NW for that.

AComben’s picture

Rerolling #105 against latest 8.3.x

tedbow’s picture

Status: Needs work » Needs review

@AComben thanks for re-rolling!

Setting to "Needs Review" so the test bot runs

DamienMcKenna’s picture

DamienMcKenna’s picture

Never mind, sorry.

dawehner’s picture

+++ b/core/modules/link/src/Normalizer/EntityLinkItemNormalizerTrait.php
@@ -0,0 +1,73 @@
+    list($target_entity_type_id, $target_entity_id) = $this->getEntityPathParts($link_normalization);
...
+  protected static function getEntityPathParts($link_normalization) {
+    $path = parse_url($link_normalization['uri'], PHP_URL_PATH);

I'm wondering whether this method would better just accept the URI. It'd be a bit more obvious what its actually doing.

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

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tedbow’s picture

Version: 8.4.x-dev » 8.5.x-dev
FileSize
2.23 KB
30.9 KB

#113 @dawehner that sounds better, fixed.

Wim Leers’s picture

Title: Menu link content entities that point to nodes are not deployable » [PP-1] Menu link content entities that point to nodes are not deployable
Status: Needs review » Postponed
Related issues: +#2871591: Allow ComplexData in TypedData to specify computed properties that should be exposed in normalization and other contexts
+++ b/core/modules/link/src/Normalizer/LinkItemNormalizer.php
@@ -0,0 +1,82 @@
+        $link['target_uuid'] = $target_entity->uuid();

This is adding something that exists only in the normalization. Which means it won't exist in OpenAPI documentation.

If #2871591: Allow ComplexData in TypedData to specify computed properties that should be exposed in normalization and other contexts would be in, then we would be able to just add this as a property on LinkItem and have it work automatically.

tacituseu’s picture

Wim Leers’s picture

#2871591: Allow ComplexData in TypedData to specify computed properties that should be exposed in normalization and other contexts is in, #2910211: Allow computed exposed properties in ComplexData to support cacheability. is the last remaining blocker (was split off from #2871591 to make its scope narrower and help it land sooner), and that too is now RTBC!

Wim Leers’s picture

Title: [PP-1] Menu link content entities that point to nodes are not deployable » MenuLinkContent entities pointing to nodes are not deployable: LinkItem should have a "target_uuid" computed property
Assigned: tedbow » Unassigned
Issue summary: View changes
Status: Postponed » Needs review
Issue tags: +Needs issue summary update
FileSize
4.78 KB
17.32 KB
70.29 KB

#2910211: Allow computed exposed properties in ComplexData to support cacheability.. also landed, this is now fully unblocked!

I've rerolled #115 entirely in the spirit of #2871591: Allow ComplexData in TypedData to specify computed properties that should be exposed in normalization and other contexts. This reuses only the logic bits from prior patches, it removes all the normalizers.

This will still need test coverage, I should be able to recycle some of the test coverage of prior patches. For now, please just review for the overall approach.


The result in the REST module:

And together with #2921257-10: On Drupal 8.5, JSON API should respect Typed Data's new ::isInternal(), and JSON API Extras should use ::setInternal(), it even works automatically in the contrib JSON API module:

Status: Needs review » Needs work

The last submitted patch, 119: 2577923-119.patch, failed testing. View results

larowlan’s picture

nice!

Version: 8.5.x-dev » 8.6.x-dev

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

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

c_archer’s picture

Has there been any update on progressing this forward so we can have menu links exported with a node?

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

johnwebdev’s picture

FileSize
5.55 KB
822 bytes

👏 2 years later and patch still applies, and works with Default Content module, 🎉

While working on some basic test coverage I noticed that the computed property won't actually change when URI property is changed. Thus the test will fail.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

pookmish’s picture

Patch in #127 was working well for the most part but it would fail if the user enters an external link in the UI. The attached patch just does a simple check for that.

johnzzon’s picture

+++ b/core/modules/link/src/LinkTargetEntityUuid.php
@@ -83,7 +83,11 @@
+    if (count($entity_parts) < 2){

Nitpick: Code style error here. Should be a space between parenthesis and opening curly brace.

narendra.rajwar27’s picture

Assigned: Unassigned » narendra.rajwar27
narendra.rajwar27’s picture

Status: Needs work » Needs review
FileSize
1.75 KB
5.9 KB

Updated patch for comment #130 and also rerolled patch for 9.1.x

Status: Needs review » Needs work

The last submitted patch, 132: 2577923-132.patch, failed testing. View results

narendra.rajwar27’s picture

Assigned: narendra.rajwar27 » Unassigned
Hardik_Patel_12’s picture

Assigned: Unassigned » Hardik_Patel_12

working on this.

Hardik_Patel_12’s picture

Assigned: Hardik_Patel_12 » Unassigned

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

larowlan’s picture

Category: Bug report » Feature request
Issue tags: +Bug Smash Initiative

In retrospect, I think this is a feature request.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

larowlan’s picture

  1. +++ b/core/modules/link/src/LinkTargetEntityUuid.php
    @@ -0,0 +1,145 @@
    +    $uri = parse_url($link_item->uri);
    

    we can use the second argument here PHP_URL_SCHEME

  2. +++ b/core/modules/link/src/LinkTargetEntityUuid.php
    @@ -0,0 +1,145 @@
    +    $this->ensureComputedValue();
    +    return $this->value === FALSE ? FALSE : $this->value->getCacheTags();
    ...
    +    $this->ensureComputedValue();
    +    return $this->value === FALSE ? FALSE : $this->value->getCacheContexts();
    

    these need to be empty arrays to comply with the interface, not FALSE.

  3. +++ b/core/modules/link/src/LinkTargetEntityUuid.php
    @@ -0,0 +1,145 @@
    +    $this->ensureComputedValue();
    +    return $this->value === FALSE ? FALSE : $this->value->getCacheMaxAge();
    

    this should default to \Drupal\Core\Cache\CacheBackendInterface::CACHE_PERMANENT, not FALSE

mohit_aghera’s picture

Assigned: Unassigned » mohit_aghera
mohit_aghera’s picture

Assigned: mohit_aghera » Unassigned
Status: Needs work » Needs review
FileSize
8.62 KB
4.65 KB

Fixing all the issues mentioned in #141

Updated default value of the computed field to NULL, instead of false. Few test cases are passing now. Let's see how it goes.

Status: Needs review » Needs work

The last submitted patch, 143: 2577923-141.patch, failed testing. View results

mohit_aghera’s picture

Status: Needs work » Needs review
FileSize
9.26 KB
655 bytes

Fixing another test case failure.
Past test case failures have been addressed now.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

nod_’s picture

Status: Needs review » Needs work
Issue tags: -Needs issue summary update

Issue summary was updated in #49 and #119.

The patch doesn't apply to 10.1

pradhumanjain2311’s picture

Status: Needs work » Needs review
FileSize
5.09 KB

Try to fix patch #145 for 10.1.x.
please review.

nod_’s picture

Status: Needs review » Needs work

Please make sure to run ./core/scripts/dev/commit-code-check.sh before uploading a patch to make sure there are no issues with code formatting. see https://www.drupal.org/docs/develop/development-tools/running-core-devel...

There is a whole file missing from your reroll.

pradhumanjain2311’s picture

Status: Needs work » Needs review
FileSize
8.97 KB
5.09 KB

Try to fix patch #150.

Status: Needs review » Needs work

The last submitted patch, 152: 2577923-152.patch, failed testing. View results

mohit_aghera’s picture

- Fixing the test case failures.
I think one of the issue was a miss in the re-roll. Fixed that.
There was other issue which was throwing warning, included that fix as well.

All failing test cases are passing on local now.

mohit_aghera’s picture

Status: Needs work » Needs review
gaurav-mathur’s picture

Patch has #154 applied successfully on drupal version 10.1.x and working fine.
Thank you

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative, +Needs change record, +Needs issue summary update

The new functions being added should be typehinted.

Can the issue summary please be updated. The proposed solution mentions hal which isn't in core anymore.

Change record was created in 2016 so probably needs an update as well.

Would be worth pointing out if this has any affect on core or if this allowing contrib modules to export menu links.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.