ECA Render: use token for render link fails

Created on 18 January 2024, 10 months ago
Updated 2 May 2024, 7 months ago

Problem/Motivation

When trying to store a link render array from the \Drupal\eca_render\Plugin\Action\Link action plugin, DataTransferObject is throwing an exception because the render array contains a URL object which is not allowed in line 297 of \Drupal\eca\Plugin\DataType\DataTransferObject::setValue where it throws this exception:

throw new \InvalidArgumentException("Invalid values given. Values must be of scalar types, entities or typed data objects.");

Not sure, if other render arrays may have similar issues. So far, I haven't found any.

🐛 Bug report
Status

Fixed

Version

2.0

Component

Code

Created by

🇩🇪Germany jurgenhaas Gottmadingen

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @jurgenhaas
  • 🇩🇪Germany jurgenhaas Gottmadingen

    Here is a blog post on how to deal with TypedData: https://mglaman.dev/blog/typed-data-api-example

  • 🇩🇪Germany qichanghai Munich

    Just as supplementary note, I think this error only happens when using the action plugin and chose to assign the link to a token(by specifying token name). We often use it to directly render a link(without specifying a token name) then it works fine.

    But it's true this issue should be fixed as we support this use case. I can see two possible fixes:

    1. Serialize the render array before set the token data, then we only need to store the serialized data as DataTransferObject, it should be supported.
    2. Add support for URL data type in DataTransferObject.

    The option 1 seems be easier, but it depends how we suppose the stored link value will used, if we again need to unserialize it and store it to another token, then we again face the same issue.

  • 🇩🇪Germany jurgenhaas Gottmadingen

    That sounds perfectly right. And I would hope we could go for option 2. That's why I copied the link from Matt's blog post, as this may help us to implement that. It will mean that this now "only" resolves the issue for URLs and not for any other objects that may occur later, but we should address this one by one as such requirements get identified.

    @qichanghai is there any chance you could have a look into this?

  • 🇩🇪Germany qichanghai Munich

    I agree the option 2 would be a better solution in the long run. Thanks for share the blog post and I'm happy to look into how to implement this solution.

  • 🇩🇪Germany jurgenhaas Gottmadingen

    @qichanghai any update on this one? Would be great if we could move this forward somehow. Please let me know if we can assist you in any way.

  • Assigned to mxh
  • 🇩🇪Germany mxh Offenburg
  • Issue was unassigned.
  • Status changed to Needs review 7 months ago
  • 🇩🇪Germany mxh Offenburg

    Created !419 where I've added a typed data wrapper for URL objects and added support for it into the DataTransferObject. Another step I've added for any unspecified object that can be cast to a string, so that should raise the compatibility a bit more.

    Worth noting that !419 only works for 2.0.x, it needs an extra backport MR for 1.1.x since typed data plugins started supporting PHP attributes starting in 10.3 (#[Data(...)), before that only Doctrine annotations (@DataType(...)) are supported.

  • Pipeline finished with Failed
    7 months ago
    Total: 426s
    #149487
  • Pipeline finished with Failed
    7 months ago
    Total: 541s
    #149492
  • Pipeline finished with Success
    7 months ago
    Total: 467s
    #149964
  • Status changed to Needs work 7 months ago
  • 🇩🇪Germany jurgenhaas Gottmadingen

    That's looking very promising. Unfortunately, \Drupal\eca\Plugin\DataType\DataTransferObject::getString calls Yaml::encode($values) which contains the URL in the render array. That leads to the following exception:

    Object support when dumping a YAML file has been disabled..
    #0 /var/www/html/web/modules/contrib/eca/src/Plugin/DataType/DataTransferObject.php(393): Drupal\Component\Serialization\Yaml::encode()
    #1 /var/www/html/web/modules/contrib/eca/src/Plugin/DataType/DataTransferObject.php(400): Drupal\eca\Plugin\DataType\DataTransferObject->getString()
    #2 /var/www/html/web/modules/contrib/eca/eca.tokens.inc(171): Drupal\eca\Plugin\DataType\DataTransferObject->__toString()
    #3 [internal function]: eca_tokens()
    

    Looks like the problem is, that the token contains a render array which gets encoded. But we actually to want the array back at that point, don't we?

  • 🇩🇪Germany jurgenhaas Gottmadingen

    I should probably mention the scenario: I created a link render element and stored it in a token. Later in the chain, I used a markup render action and wanted to embed the token into that. I can see, that this attempts to convert the token into a string. But it should probably rather render it at this point?

    Maybe this needs to be addressed in a separate issue, now that I talk about it. It seems to be unclear, at least to myself, how to store a render action value into a token for later use. Not only that, I assumed that the render action value would not be output at that point when it gets stored into a token, but that's probably a false assumption.

  • Pipeline finished with Success
    7 months ago
    Total: 486s
    #150057
  • Status changed to Needs review 7 months ago
  • 🇩🇪Germany mxh Offenburg

    I've added a further step into the getString method to avoid objects within the array that is about to be encoded to Yaml in https://git.drupalcode.org/project/eca/-/merge_requests/419/diffs?commit...

    For the raised concern in #11 I've added a render step. However this might be a behavior change that should only be included in 2.0.x, if that should be included anyway.

  • Pipeline finished with Success
    7 months ago
    #150076
  • Status changed to RTBC 7 months ago
  • 🇩🇪Germany jurgenhaas Gottmadingen

    This works like a charm, thank you so much @mxh, great work. And the idea to render arrays when they contain certain keys is probably the best we can do at that point.

    When it comes to back porting, I'm uncertain how we should treat that one. Even though the render piece is a change behaviour, I wouldn't expect anyone to have taken value out of a render array in a token just yet. Therefore, I would tend to back port the whole thing.

    As for the token usage in render action plugins, should I open a new issue to talk about the question if and how we could prevent the output of the render plugin when a token is being used?

  • 🇩🇪Germany mxh Offenburg

    When it comes to back porting, I'm uncertain how we should treat that one.

    It's up to you :) don't know if and how someone is already using that particular feature.

    As for the token usage in render action plugins, should I open a new issue to talk about the question if and how we could prevent the output of the render plugin when a token is being used?

    Yes I think it makes sense to handle that one separately.

  • Pipeline finished with Skipped
    7 months ago
    #150327
  • Pipeline finished with Skipped
    7 months ago
    #150328
    • jurgenhaas committed 10a638c0 on 1.1.x
      Issue #3415579 by mxh, jurgenhaas, qichanghai: ECA Render: use token for...
  • Status changed to Fixed 7 months ago
  • 🇩🇪Germany jurgenhaas Gottmadingen

    I've merged and back ported this to 1.1.x

    Also opened the follow-up issue 📌 ECA Render: how to prevent output of render action when token name defined for later use Active

  • Pipeline finished with Failed
    7 months ago
    Total: 359s
    #161882
  • Pipeline finished with Success
    7 months ago
    Total: 1346s
    #161888
  • Automatically closed - issue fixed for 2 weeks with no activity.

  • Pipeline finished with Success
    1 day ago
    Total: 564s
    #344969
  • Pipeline finished with Canceled
    1 day ago
    Total: 385s
    #345034
Production build 0.71.5 2024