Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

!!! FEATURE: Overhaul node uri building #4892

Merged
merged 21 commits into from
Jun 23, 2024

Conversation

mhsdesign
Copy link
Member

@mhsdesign mhsdesign commented Feb 15, 2024

Resolves: #4552

Introduces a new API for node-uribuilding to replace the LinkingService
Currently Neos9-Beta10 does already contain a similar new NodeUriBuilder but this change overhauls the API to not expose the implementations of the Flow UriBuilder.

Upgrade instructions

The new NodeUriBuilder is not a singleton and thus cannot be injected but must be created via the NodeUriBuilderFactory with the current ActionRequest at hand.

Simple case:

// before
#[Flow\Inject]
protected LinkingService $linkingService;

public function uriForNode(Node $node, ControllerContext $controllerContext): string
{
    return $this->linkingService
        ->createNodeUri(
            controllerContext: $controllerContext,
            node: $node
        );
}
// after
#[Flow\Inject]
protected NodeUriBuilderFactory $nodeUriBuilderFactory;

public function uriForNode(Node $node, ActionRequest $actionRequest): UriInterface
{
    return $this->nodeUriBuilderFactory
        ->forActionRequest($actionRequest)
        ->uriFor(
            NodeAddress::fromNode($node)
        );
}

Advanced case:

// before
#[Flow\Inject]
protected LinkingService $linkingService;

public function uriForNode(Node $node, ControllerContext $controllerContext): string
{
    return $this->linkingService
        ->createNodeUri(
            controllerContext: $controllerContext,
            node: $node,
            format: 'json',
            absolute: true,
            arguments: ['simple-query' => 'abc'],
            section: 'my-anchor'
        );
}
// after
#[Flow\Inject]
protected NodeUriBuilderFactory $nodeUriBuilderFactory;

public function uriForNode(Node $node, ActionRequest $actionRequest): UriInterface
{
    $resolvedUri = $this->nodeUriBuilderFactory
        ->forActionRequest($actionRequest)
        ->uriFor(
            NodeAddress::fromNode($node),
            Options::create(forceAbsolute: true)->withCustomFormat('json')
        );

    return UriHelper::uriWithAdditionalQueryParameters($resolvedUri, ['simple-query' => 'abc'])
        ->withFragment('my-anchor');
}

Also notice that the PHP api for uri building will no longer keep the current format of the action request by default unlike in the Fusion api.
If this behaviour is required it should be implemented via $options->withCustomFormat($actionRequest->getFormat());

Review instructions

Currently in 9.0-dev the NodeUriBuilder is a not well though out abstraction. It has a really shallow implementation and doest abstract the uribuilder away, but rather exposes it to be set from outside. That makes it impossible to swap out the implementation and also the api is questionable. How do i really set the format option or add additional queryparameters?

With the overhaul of the api and lately new introduced Shared\NodeAddress we can go one step further and not use the legacy FrontendRouting\NodeAdress any further. The new address will fill its place and make thus also cross site linking will be possible: #4441

We decided against adding the query parameters to be encoded as array option to the NodeUriBuilder Options and promote to use the helper UriHelper::uriWithAdditionalQueryParameters.
It is better to have it separated into a helper because its not core PSR standard behaviour (where the query is just a string) and anything further like http_build_query is php magic which does not obey an official standard.
Also another argument is that its just string manipulation after the resolve was successful for the same reason a fragment cannot be provided as option but must be set via the PSR Api withFragment.

Adjustment prs:

Related discussions:

Checklist

  • Code follows the PSR-2 coding style
  • Tests have been created, run and adjusted as needed
  • The PR is created against the lowest maintained branch
  • Reviewer - PR Title is brief but complete and starts with FEATURE|TASK|BUGFIX
  • Reviewer - The first section explains the change briefly for change-logs
  • Reviewer - Breaking Changes are marked with !!! and have upgrade-instructions

@github-actions github-actions bot added the 9.0 label Feb 15, 2024
@mhsdesign mhsdesign marked this pull request as draft February 15, 2024 09:40
@mhsdesign mhsdesign force-pushed the feature/overhaulNodeUriBuilding branch from a5e9319 to a90fddb Compare February 16, 2024 09:13
@mhsdesign mhsdesign force-pushed the feature/overhaulNodeUriBuilding branch 3 times, most recently from ad7df6c to f3f34f9 Compare February 22, 2024 08:35
@mhsdesign mhsdesign force-pushed the feature/overhaulNodeUriBuilding branch from f3f34f9 to d32a2d4 Compare March 19, 2024 22:54
@mhsdesign mhsdesign force-pushed the feature/overhaulNodeUriBuilding branch from d32a2d4 to b90b043 Compare May 11, 2024 18:38
@mhsdesign mhsdesign changed the base branch from 9.0 to task/workspaceAwareNode May 11, 2024 18:40
@mhsdesign mhsdesign force-pushed the task/workspaceAwareNode branch 2 times, most recently from 5c1e131 to 95ea686 Compare May 13, 2024 13:48
@kitsunet kitsunet deleted the branch neos:9.0 May 13, 2024 17:24
@kitsunet kitsunet closed this May 13, 2024
@mhsdesign mhsdesign reopened this May 13, 2024
@mhsdesign mhsdesign changed the base branch from task/workspaceAwareNode to 9.0 May 13, 2024 18:34
@mhsdesign mhsdesign force-pushed the feature/overhaulNodeUriBuilding branch from 6489bc9 to 8a2748f Compare May 13, 2024 19:02
@mhsdesign mhsdesign mentioned this pull request May 16, 2024
10 tasks
@mhsdesign mhsdesign force-pushed the feature/overhaulNodeUriBuilding branch 3 times, most recently from be04b6d to abed60a Compare May 16, 2024 11:31
@mhsdesign mhsdesign force-pushed the feature/overhaulNodeUriBuilding branch from abed60a to e953cd9 Compare May 19, 2024 08:56
@mhsdesign mhsdesign marked this pull request as ready for review May 19, 2024 09:56
*
* See also {@link https://docs.neos.io/guide/rendering/rendering-special-formats}
*/
public function withCustomFormat(string $format): self
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i also noticed that the current format will NOT be takend from the actionRequest so one would need to take care of this themselves is this ok?

Copy link
Member Author

@mhsdesign mhsdesign Jun 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But i guess the Fusion helpers should default to the requests format? Either in php or better via

format = ${request.format}

what do you think? ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question, I'm not sure about that. When I played with HTMX, I used a custom format for the HX requests (see https://github.com/bwaidelich/Wwwision.HtmxTest/blob/main/Resources%2FPrivate%2FFusion%2FComponents%2FHtmxUri.fusion)
In the results I would not want this format to be used for all links implicitly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently it's the expected behavior, I have had it in both directions in projects. Sometimes I was happy it would automatically keep the xml I had in hte current request without me having to check it at every link, other times I would have wished to ignore it and use html by default 🤷

Copy link
Member Author

@mhsdesign mhsdesign Jun 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i guess for fusion (especially as the magic is currently still part of the Neos.Fusion:ActionUri) i think it would make sense to keep it for the Neos.Neos:NodeUri as well.

Ill vote for making it a default value on fusion side so its directly visible to the human eye? or should it be part of the fusion php implementation?

edit on the other hand this is core behaviour and has to be documented via comment. Otherwise it would be weird that we access the request differently in two places (once for the uri builder and then for the format)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My gut feeling is still: html is like the 99% case and I would want to explicitly change that if I wanted to create links to other resources in the same format (e.g. in a JSON response I might want to link to other JSON resources, but I would expect the node URI to still have the default format:

{
  "title": "foo",
  "contactUri": "https://domain.tld/contact",
  "includedResources": {
    "contacts": [
      {"id": "123", "href": "/api/contacts/123.json"}
    ]
  }
}

Or maybe I can override the default format for the RoutingDefaults per controller/action?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the magic of keeping the format either has helped (by knowing it beforehand) or worse lead to confusion and i had to debug many times (because i forgot) why uri building failed ... the @format: json part in the exception dump cat Data... tends to go unnoticed for the untrained eye.
Still for this change it would be cruel to change behaviour like this ever so slightly and id prefer a dedicated discussion and separate pr.
I think we only have to agree that the PHP Node Uri building api doesnt do it by default and how to implement this magic again for the Fusion prototypes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense ... to me.

I would be fine with simply adding a default format of "html" to the fusion prototypes that is documented.

That way you only have to read the fusion documentation to get it and not know about some magic behavior that works until you forget it and then causes trouble.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im not against removing the format by request magic but id prefer a separate pr for that (and probably wont do it myself right now because i cant sell it as well as you do :D)
I guess this pr is a step in the right direction by removing that feature from the core node uribuilding and making it opt in from the outside. That means we can eventually get rid of it!

…uilding uris from Fusion or Fluid

The magic of keeping the format either has helped (by knowing it beforehand) or worse lead to confusion and hard to debug uri building errors (the `@format: json` part in the exception dump tends to go unnoticed for the untrained eye)

Still for this change it would be cruel to change behaviour like this so we reimplement it.
The filter like signatures dont feel quite right because they only have one argument ... and its a yagni to add new args
Copy link
Member

@kitsunet kitsunet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Giving this 👀
Might do some more testing tomorrow, if it doesn't get merged.

Copy link
Member

@mficzel mficzel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 By 👀 and 🧪

Should be tested with: neos/neos-ui#3802 as otherwise you end up with errors in the backend.

@@ -7,7 +7,6 @@
uriPattern: 'neos/preview'
defaults:
'@action': 'preview'
appendExceedingArguments: true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\o/ ... yeha that alone is worth it ... if only this would be the main fe route. I fear this needs appendExceedingArguments a while longer

*
* See also {@link https://docs.neos.io/guide/rendering/rendering-special-formats}
*/
public function withCustomFormat(string $format): self
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense ... to me.

I would be fine with simply adding a default format of "html" to the fusion prototypes that is documented.

That way you only have to read the fusion documentation to get it and not know about some magic behavior that works until you forget it and then causes trouble.

@mhsdesign mhsdesign merged commit 0f2a323 into neos:9.0 Jun 23, 2024
10 checks passed
@mhsdesign mhsdesign deleted the feature/overhaulNodeUriBuilding branch June 23, 2024 20:10
@mhsdesign
Copy link
Member Author

Thank you so much for all the reviews and discussions ;) Glad to have this merged!!! One step closer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Discuss LinkingService vs the NodeUriBuilder
4 participants