Problem/Motivation
On #3041924: [META] Convert hook_help() module overview text to topics we are converting our hook_help() text into Help Topics (and making improvements). As part of that effort, on #3072312: Review/fix/delete existing help topics, we are going through the initial topics we added as proof of concept when the original Help Topics patch went in. We came across a problem that is sort of a regression from things we could do in hook_help() that we can't currently do in a help topic.
In hook_help(), we could have code like this, to make a link only if another module exists:
$url = (\Drupal::moduleHandler()->moduleExists('block')) ? Url::fromRoute('help.page', ['name' => 'block'])->toString() : '#';
But we don't have a way to do that in a Twig template.
We also don't have a way to verify access before we put links in, so we may be leading users to 403 pages. This was also true in hook_help().
As a note, we actually don't even have a good way to make URLs at all in Twig -- see this related issue: #2996305: Add support for the url() function to twig {%trans%}
Proposed resolution
Make a dedicated function for help topic Twig templates that outputs either a link or plain text. It should avoid throwing exceptions for things like route not found (perhaps a module isn't installed), invalid/missing parameters (maybe a topic can't be found), and it should not make a link that a given user cannot visit. In those cases, plain text would be put out, and if all is well, a link would be put out.
Since about half the links in our topics are links to other topics, it would be really helpful to also have a function that outputs a link to a topic, using the topic title as a link text.
Remaining tasks
Make/review/commit a patch that adds safe link functions for help topics: one for generic routes with generic link text, and the other for help topics with the topic title as link text. If the link is not accessible, or a route/parameter problem happens during link generation, plain text should be returned instead of a link.
Follow-up needed:
Issue: #3192585: Fix up topics to use new help_topic_link function
That issue is to make sure we:
- Fix up all the topics to use the new functions.
- Enforce their usage in help topics rather than the Twig base url() function. This can be added to the existing help topics syntax test.
- Update the help topic standards page to use this new function. https://www.drupal.org/docs/develop/documenting-your-project/help-topic-...
User interface changes
a. Missing routes and parameters in URLs will not cause PHP exceptions on Help Topics pages.
b. Links generated in Help Topic pages will not take users to 403 pages.
c. In both of those cases, the link text will still show up as plain text.
API changes
No changes to existing APIs, but new Twig functions will be added for help topics to accomplish the above. Change record: New functions for making links in Help Topics
Data model changes
None.
Release notes snippet
Probably does not need to go into release notes, as this is still Experimental.
| Comment | File | Size | Author |
|---|---|---|---|
| #97 | 3090659-97.patch | 17.47 KB | jhodgdon |
| #97 | interdiff-95-97.txt | 1.06 KB | jhodgdon |
Comments
Comment #2
larowlanI wonder if the existing twig url function could catch route not found issues and just emit the anchor text instead?
Comment #3
jhodgdonIs there an existing Twig URL function? See also #2996305: Add support for the url() function to twig {%trans%}
Comment #4
larowlanYes there is, that issue is to have it work inside a trans tag
Comment #5
jhodgdonDoh, right. :) So yes, that does sound like a good way to implement this functionality.
Comment #6
larowlanComment #7
larowlanComment #8
larowlanComment #9
jhodgdonHm.... This is interesting, but not what we really want to happen in help topics normally:
What we usually want to happen is to make a link to either another topic or an admin page if the URL exists, and if it doesn't exist, we want the text there but either for it not to be a link or to just link to # so it's not broken.
So the logic we want would usually be something like "If the URL is found, use it, and otherwise use # for the URL".
Also I've been told we should not mix things in the help topics module (currently experimental) with things in Core in general, in the same patch... so probably the test inside help topics doesn't belong in this patch.
Comment #10
larowlanYeah, so I think we can get rid of the
{%set %}stuff if we just return FALSE instead of an empty render array with cache tags.But I'm not sure if that could end up with stale render cache entries if e.g. a new route was added dynamically somehow.
So we might need to tag Wim or Daniel for advice on that, I'll ping them in slack
Comment #11
larowlanFor reference `\Drupal\Core\EventSubscriber\CacheRouterRebuildSubscriber` is where the 'route_match' tag is invalidated on route rebuild
Comment #13
ghost of drupal pastWhat's the targeted PHP version here? I lost track. PHP 7.1+ can do
catch(Foo | Bar $e)Comment #14
larowlan😂I had the same discussion with myself and just went with the safest option because I wasn't sure either
Comment #15
ghost of drupal pastJust for the record, 8.9 seems to be 7.0.8 and 9.0 seems to be 7.2.3.
Comment #16
jhodgdonCouldn't stand the typo any more. :)
Comment #17
andypostI think better to stick on 7.0.8 syntax because it is set for 8.8.x
Comment #18
ghost of drupal pastThere was a discussion on slack where berdir said:
and Fabianx added later:
Not quite sure what that means implementation wise. "Directly" would be
$this->renderer->getCurrentRenderContext()->update($element)where$elementcould be the$emptyarray from this patch but that method is protected. Thus, I think$this->renderer->render($empty)would work because that, eventually, does a call to the sameRenderContext::update. I will ask Berdir to verify this.Comment #19
andypostRe-roll and clean-up of #7
Comment #20
andypostProper re-roll
Comment #21
jhodgdonAdding note to summary that this also applies to 403 (no permission).
Comment #22
pratik_kambleComment #23
pratik_kamble@andypost thanks for the patch. I have reviewed the patch. Twigs URL function does not throw any error if route not found or for missing parameter exceptions.
Patch LGTM. Just one minor change, docblock indentation was incorrect. Attaching new patch to fix it.
Comment #24
pratik_kambleComment #25
abhisekmazumdarComment #26
andypostSlightly related
Comment #27
abhisekmazumdarLooks good to me.
Comment #28
abhisekmazumdarComment #29
chi commentedHaving those exceptions was a big advantage of route based link generation. Twig templates was kind of "protected" from having broken links. With this patch using routes over paths to build links would not make much sense anymore.
Comment #30
catchAgreed with #29 I think this needs more discussion.
Comment #31
jhodgdonWould it be possible to add something to $options that would let you say either "fail with an exception" or "return null" or even "return '#'" as the on-exception behavior? That way some Twig templates, like help templates, could use the "return '#'" option, and the default behavior or "fail with an exception" could continue for those who want it.
So maybe it would be:
$options['error_behavior']
with possible values:
- 'exception'
- 'null'
- any other string (that string will be returned if there is an exception)
Comment #32
berdirI still struggle with what the exact use case here is, IMHO we might be trying to address the wrong problem. The issue summary has this example:
The condition isn't, does this route exist, but does this module exist. So why not provide a twig function or something for a module exists check? Isn't that the 99% reason for this kind of logic? You're not going to write hardcoded twig templates for some dynamic routes. Right now, in a regular template, you would do that in a preprocess, set a flag and then you can easily do whatever you want in twig with the result of that check.
Comment #33
jhodgdonThere are the types of links we are making in topics:
a) Topic to topic cross-links in the text. What I've been doing when writing topics is only making links in the text from topic A to B if they are either from the same module, or if B is a dependency of A, to avoid the problem of a topic not existing and the URL failing to compute.
b) Related topics section -- for this we do not use the Twig template at all. It's just a list of machine names of topics and the help system turns them into links if they exist, and ignores if they don't.
c) Links to admin pages in the text. This is probably the main use case for this issue. For example, in a page about how to create a view, the first step would be "Navigate to Admin > Structure > Views" and "Views" would be a link to the admin/structure/views page. This link could conceivably not be available to the person reading the help topic, or could conceivably be not defined if the views_ui module was not present. However, that second problem is not an issue in topics, in practice, because the topic that needs a particular admin page link is owned by the module that defines the route, or a module that it depends on (in this example, they are in the views_ui module namespace). It is possible that the person reading the topic does not have permission to go to that link, but I think the link still gets made and they get a 403.
As a note, we are not linking to module names the way we did in the hook_help (as illustrated in the issue summary example and comment #32), where we would link to the main module overview help page.
I guess in the 8 months since this issue was created, we went from a "we need to reproduce what we can do in hook_help" mentality to a "this new system can be used in different ways from hook_help" mentality, and it's possible we don't need this now.
Comment #34
berdir> It is possible that the person reading the topic does not have permission to go to that link, but I think the link still gets made and they get a 403.
That's not really how everything else works. If you don't have access to a node, we don't show a teaser or link. If a menu link points to a page you don't have access to, it doesn't show.
I didn't think about acess though, so there's more dynamic parts than just the module being enabled or not. I still think that making things more explicit with conditions and checks is preferable over suppressed error handling and just returning nothing. We could do path_accessible('route_name') or so, and then you have full control over whether you want to hide the part about views_ui if it's not enabled or allowed to be accessed, or you could show a message that say something different. That's what I've seen a few times in contrib settings pages for example ("enable module X to do this" vs. "go there to configure module X behavior")
Comment #35
jhodgdonI agree that we do not show links the current user cannot see in menus, node tabs, views, and other places. However, the Url class itself, as far as I know, does not check access when making links. I think the caller has to check access, and the menu, node, and views modules do that checking.
I don't think we checked access in hook_help() when we linked to admin pages either.
Comment #36
berdir> I think the caller has to check access, and the menu, node, and views modules do that checking.
True, I think it doesn't do that automatically, but it has an access() method and interestingly, when you go through a render array, it includes an access check automatically: \Drupal\Core\Url::toRenderArray(). But path() in twig doesn't do any checks.
> I don't think we checked access in hook_help() when we linked to admin pages either.
Well, that doesn't mean that we can't improve it :)
Comment #37
jhodgdonAll good points. Taking all of that into account...
a) What we're currently doing in the Help Topic Twig templates (which contain the topic text) for URLs is code that looks like this:
Some of the url() calls have additional variables, but that's basically it.
b) For this application, I really don't think we want to do a lot of logic and checking and contingencies... What we really want is an easy way (preferably, one function call) that would generate the URL if the route/parameters are valid and the user can access it, and return '#' if not so that the text in the help topic still works. If there are too many contingencies in the Twig file, it's not so easy for non-programmers to write or edit the documentation, and translation also becomes more difficult.
c) See also #2996305: Add support for the url() function to twig {%trans%}
Comment #38
fabianx commentedI would suggest to scope that to the help module, create a help_url() helper as a Twig Extension and add the exception code into there.
Makes it also easier to return just a '#' sign, which is pretty unique requirement for the help system.
That nicely scopes it, does not change behavior and can easily be upgraded later to call something in core if / when something exists for doing that (like an option `ignore_exception => TRUE`).
Feel free however to move the component and state back if you think this really belongs into the theme system already. (This is just my suggestion to move this issue forward).
Comment #39
jhodgdonGreat idea -- I think this is the right solution.
Comment #40
jhodgdonOK, I think what we would need to do to make this happen is:
a) Define a help_topics.services.yml file with an entry something like this:
(Not sure if both of those arguments are needed?)
b) Define the HelpTwigExtension class. It would need some of the constructor stuff from the TwigExtension class that is being patched in the latest patch, and it would define methods:
c) The tests from this patch, but put them into a new test class under core/modules/help_topics.
d) Replace all calls to url() in existing committed help topics Twig files (in core/modules/help_topics/help_topics) to use help_url() instead.
Comment #41
jhodgdonI'm working on a patch for this.
Comment #42
jhodgdonHere's a patch that implements #40. The unit test in the patch passes locally, and I also tested several of the help topics that were updated to use the new function, and their URLs are fine.
In addition to what is in #40, I added a bit of code for a functional test, which adds a nonexistent route URL to one of the test help topics, and verifies that the link is there with URL '#'. This test passes too.
I didn't make an interdiff, since there is no real overlap between the previous patch and this one (although I used quite a bit of the code, it is in different files).
Comment #43
andypostFew code style issues, but looks great!
Comment #44
chi commentedThat's too generic. I think we should only cover issues described in the issue summary (i.e. route not found). For any other problems the function should still fail. So this could be either a list of specific exceptions or anything implementing Symfony\Component\Routing\Exception\ExceptionInterface. I would prefer to be as specific as possible.
Can this have an explanation of what kind problems are expected? That would also explain the purpose of having another URL helper.
nitpick, keeping
trysection small may help to understand where exactly exceptions are expected.Something like this.
Comment #45
jhodgdonI disagree about the exceptions being more specific. This function is in the help_topics module, and is only for help topics. For this purpose, someone is trying to view a help topic because they need to learn how to do something. I think we don't want the whole topic to not display because something failed in making one link -- the person viewing the topic will most likely not know what is wrong or how to fix it. That is the whole point of this -- we want a fail-safe way to make links, only for help topics, which should be visible if it is at all possible.
Regarding having more code in the try {} vs. more code in the catch {}, I am ambivalent. If someone wants to redo the patch and rearrange it, that is fine with me.
Comment #46
andypostAddressed review #44
I agree that better to catch only URL generation exceptions, to be more strict when something will change in routing.
Also added code comment to catch section about this cases (test coverage only for this cases all over core)
OTOH I'm fine to use non-specific
Exceptionbut prefer to be more strictPatch also fix CS issues and type-hints as all new code should do.
Extracted check for fallback URL build to
assertIsHelpUrlFallback()as render arrays may change some day also removes code duplicationComment #47
andypostOne more fix
Comment #48
jhodgdonSuggestion for comment that currently says:
We want to view the topic rather than throwing an exception if a route is not found or a parameter is incorrect (usually due to a missing or updated module). In this case, return a '#' as the URL.
I also think we need to update the doc block, because it currently says the URL is "safe" and that it will always return something. With the current patch, this is not the case.
So the first line should probably be:
Returns an absolute URL, given route name and parameters, checking for some exceptions.
And the @return docs second sentence should be:
If a missing route, missing parameter, or invalid parameter exception occurs, the URL returned is '#'.
Comment #49
andypostThanks for wording, using shorter description from slack
Comment #50
jhodgdonThis all looks good to me. I could not set it to RTBC, because a lot of this patch is mine from #42.
Also, I do have one question, in core/modules/help_topics/src/HelpTwigExtension.php :
It looks like this is expecting we have a method isUrlGenerationSafe() on this class, but this method does not exist? Probably my fault, but I think we either need to not declare an is_safe_callback, or copy the isUrlGenerationSafe() method from core/lib/Drupal/Core/Template/TwigExtension.php? Probably? I really don't know what the is_safe_callback thing does.
Setting to Needs work because I don't think we should be referencing a method that doesn't exit.
Comment #51
andypostHere's a fix and test that covers #50
As this link will be always rendered in topics I think we should set it to safe html, moreover no iser input could be passed here
Would be great to get eyes of security team on it
Comment #52
andypostproper tag
Comment #53
jhodgdonHm. In the file core/lib/Drupal/Core/Template/TwigExtension.php the mehtod isUrlGenerationSafe() has much more complicated logic to determine whether the URL is safe. Just saying "this is safe" doesn't make sense to me, since it's essentially the same URL generator function?
Comment #54
dwwNot a real review (yet), but a few quick questions on the latest interdiff:
Why bother with the local variable at all? Why not just:
?
If instead of casting these values, why not just assertEquals() ?
Comment #55
andypostRe #54
1) easy to debug when it's a variable to dump
2) thank you!
fixed both
Comment #56
jhodgdonI still don't think #51 was the correct fix for #50. I think the correct fix is to either call or copy in the isUrlGenerationSafe() function from the core TwigExtension class.
Comment #57
andypostI'm also unsure, just found no difference, that's why looking for review
edit moreover I found no tests in SF about it
Comment #58
dwwRe: #55 I meant the
$rendererlocal var. You fixed$result(also not needed, good point!). ;)Comment #59
andypostLocal var for renderer useful for type-hints because I think to use it again to check results for cachability metadata provided
Comment #61
jhodgdonUpdate title to be more generic (there are other problems, such as permissions, mentioned in the issue summary).
I also took a fresh look at this patch, and I have some comments. Aside from the first item, they all pertain to the core/modules/help_topics/src/HelpTwigExtension.php file:
a) We've probably had some commits of topics since the patch was made, so they would need to be updated also to use the new Twig function to generate URLs.
b) nitpick:
We generally don't start out docs with "A class providing". This should probably just say "Twig extensions for help topics.".
c)
We need this function to also cover the case where the user does not have permission to use the route. I don't see this in the documentation or in the code or in the test.
d) The Kernel test verifies generation of an existing route, but doesn't seem to verify any of the cases that should return '#'. Should it? It does seem to be covered in the Unit test (aside from the access permissions part) and the Functional test. Honestly, I'm not sure why we have the Kernel test?
[edit, added] e) The comments from #50 and subsequent discussions about whether that was the right fix still are open questions for me.
Comment #62
jhodgdonUpdating summary.
Comment #63
jhodgdonTo get this going, I have created a new patch with some of #61 addressed (I had already worked on this issue earlier so I wasn't eligible to RTBC anyway). Things I did:
core/lib/Drupal/Core/Template/TwigExtension.php
the isUrlGenerationSafe() function has a bunch of cases, depending on the URL parameters, that only bypass escaping if the URL is definitely safe:
So I do not think it is OK to bypass that by setting is_safe to 'html'. Our choices are:
a. Copy in the isUrlGenerationSafe() function from the core TwigExtension class (ugh! copy code!) or
b. Make a trait for just that function so we can call it [we don't and can't extend the core class] or
c. Don't say our URL is safe.
In this patch, I chose to do (c). There will be a small hit in performance for the few URLs that are typically in a Help Topic template, and we won't have to worry about maintaining this function to be the same as the one in the Core class.
Since one item still needs to be done (verify permissions and return # if user has no permission), I am leaving this at Needs Work (after setting to Needs Review temporarily so we can see if it passes tests and code sniffs).
Note: I'm not sure whether we really *can* or *should* actually verify permissions. The idea was that a user shouldn't see links in topics that take them to 403 pages. But it would mean we would have to deal with caching and I'm not sure at this point in the rendering whether we have the ability to even do that? So the right answer might be that we need to live with 403 links in topics.
Comment #64
jhodgdonNo longer needs security review as we are no longer asserting that the URL is always not needing escaping. Also setting back to needs work for the end of #63. I'll see if I can get some answers in Slack about whether we can actually check permissions and properly trigger caching from within a TwigExtension.
Comment #65
jhodgdonI asked about how/whether we could do this in Slack, and got some help from fabianx (seconded by joelpittet). What I learned:
a.
b.
So, we should be able to do this. We'll need to:
- get the bubbleable metadata from the URL generator and add that to the build array (honestly I'm not sure why the core Twig url() function doesn't do this?)
- also add in an access check similar to (b) above.
Comment #66
jhodgdonI'm going to work on this today.
Comment #67
jhodgdonDoh! I should have looked more carefully at the patch we already had. We were already doing some stuff with cache tags in our URL generator.
Anyway, here's a patch that I think takes care of the access check. With tests that pass locally.
Comment #69
jhodgdonWeird. Some of those tests passed locally. Maybe I missed something in the patch, or maybe you can't inject the access manager into a Twig thing... Will take a look but not sure when. Maybe tomorrow.
Comment #70
jhodgdonDoh. Typo.
Comment #71
jhodgdonI think the Unit test should have a few lines to verify that cache stuff from the URL generation and the access check make it to the render array, just to be exhaustive. For the access check, should verify for both the no-access and the has-access check. I should have some time today to update the patch.
Comment #72
jhodgdonOK, here's one more new patch, with a few lines added to the Unit test so that it verifies cache information from both the URL and the Access object are carried through.
Comment #73
fabianx commentedIs that for this issue or a future one?
--
RTBC - except for this one comment.
Looks good to me.
Comment #74
jhodgdonI'm not seeing that @todo in the latest patch file... did you review the latest patch?
Comment #75
jhodgdonLooks like one of the help topics changed a bit and the patch doesn't apply cleanly, so rerolling.
Comment #76
fabianx commentedRe-reviewed, still RTBC
Comment #77
catchJust re-titling to more closely match the current solution.
One question here though is whether we couldn't have a help_link method that renders either a link or the raw string. The raw string is more correct for users that don't have access.
I guess though that the problem is this would make translations of help topics more piecemeal.
Comment #78
jhodgdonHm.... So here's an example of the two most common ways we are using the url function (for links to other topics, and for links to admin pages). I can think of three ways we could make this look:
a) Current patch:
b) If we had a help_link function:
c) If we had a help_link function that we embedded within the trans section:
I don't like option (c) -- it gives translators too much opportunity to screw up the parameters, such as trying to translate IDs like 'user.overview' or "node.add_page" (I see this a lot in the user guide translations). But that would seem to be the only way to keep the link text and the rest of the sentence together in a single "chunk" of translation.
Option (b) seems sort of OK to me... The UI strings that go into the link text are for the most part either help topic titles or chunks of UI text that already appear stand-alone in the UI, so they are already being translated as separate chunks of text. But, as noted in the previous comment by catch, that would make the translation more piecemeal.
Given that, my inclination is to stick with option (a). Thoughts? Other options that would be even better?
Comment #79
alexpottCan we add a followup to add a check that help_url is being used and not url in \Drupal\Tests\help_topics\Functional\HelpTopicsSyntaxTest - I don't think it needs to happen on this issue but it would be great to add their - because some people test stuff with user 1.
Comment #80
catchb) looks better than I thought it would when I wrote it, moving back to CNR for some other opinions. The ideal thing would be a patch with one help topic converted so we can compare.
Comment #81
jhodgdonHm.... I was going to write up a patch that would convert using this hypothetical help_link function as in option B in #78, but I realized I missed something -- we would need to pass the link text through Twig translation. So it would need to look something like this:
I don't know how to make the syntax work here... can you even do a % trans inside of a % set? Where do you put the quotes? This just looks wrong. ???
Comment #82
jhodgdonRegarding #79 -- once we figure out what option we're going with, I'll create a followup issue to add it to the syntax test. Adding tag now and adding note to issue summary so it doesn't get forgotten.
Comment #83
jhodgdonOh yeah, we also need to update the help topics standards once we decide, so adding that to the follow-up list.
Comment #84
jhodgdonSo, I'm not sure where to go with this, given #81. Is it possible to translate text within a set statement? If so, how? Seems messy... I'm inclined to stick with the current patch, but open to alternatives.
Meanwhile, here's a new patch that fixes up the topics in recently-committed #3095734: Convert config module hook_help() to topic(s) just like everything else in this patch. I verified that all the currently-committed topics are included in the patch too.
Comment #85
fabianx commentedHere is the syntax how it would work:
It's more piecemeal and a little bit more code, but can re-use more of existing translations and translations have nice context is variable is suffixed with _link of what the placeceholder is.
I think it can work, but leave it to others to decide what's better.
Comment #86
fabianx commentedQuick drive-by realization:
It should not be needed to render_var this.
Twig should render_var things to string automatically when output.
This is only needed when checking if something is empty or not.
Comment #87
jhodgdonThis is all very useful -- many thanks!
So... I think we should do the following:
a) Make a help_topic_link() function. It would render into a link to a help topic, using the topic's label/title as the link text. That would eliminate the need to provide the link text, because I think we are always using the topic title. It would also mean when titles of topics change, we wouldn't have to update other topics that link to them to stay consistent.
b) Make a help_link function that works as Fabinx suggested in #85. We would use that more complex structure for links to admin pages.
c) Take out the render_var calls in our set statements, because we are not using complicated logic in our templates.
I'll take a stab at this... sometime in the next few days.
Comment #88
jhodgdonHere's most of a new patch. What I did:
a) Reverted all the changes to the help topics from the previous patch, except I forgot the ones in the test module.
b) Made new Twig functions for making links to help topics and generic routes, and took out the function for making a bare URL.
c) Modified just one of the help topics to use the new functions.
d) Edited the test topics to use the new functions.
e) Got most of the tests working [see below, the TwigExtension unit test is not working.]
f) The "interdiff" file is a bit odd because it's an interdiff from (a) rather than from the last patch. And the patch is a lot smaller because I didn't go through and modify all of the help topics to use the new functions yet. I figured we should get the system working as we want it first, and then go modify all the topics.
A few additional caveats:
1. Fabianx thought we shouldn't have to use render_var (see comment #86), but I could not get the links to render without wrapping them in render_var, so I had to put that back in.
2. The
'#type' => 'link'render array expects'#url'to be a Url object, not a string and not a GeneratedUrl object. The previous patch was using an injected UrlGenerator, but the objects it produced did not work in the link, so I reverted to calling a static method on the Url class to generate the URL. Questions:- 2a: Are we supposed to use Url::fromRoute() inside classes? I guess the core TwigExtension class is using it in places, so maybe that is OK.
- 2b: This makes the Twig functions not unit testable. That's annoying. I didn't write a new test yet, and I'm not sure exactly how would be best to do it.
Comment #89
fabianx commentedLooks great to me. It's a win to just link to a topic IMHO.
1. The render_var is likely a limitation of the trans filter, but no big deal IMHO.
2. I would probably just add a helper function to Url that does Url::fromGeneratedUrl, but that's a question for alexpott or catch of how to best solve that.
Once that's fixed, the unit test will work again as there is no more global state.
Comment #90
fabianx commentedWell my idea won't work (a GeneratedUrl cannot be converted into an Url), so the second best is to just inject the link generator, which IIRC takes a generated url and just create the link yourself and not via the render array.
Comment #91
jhodgdonCouldn't we make the Link class work with a GeneratedUrl?
Let's see... Here's the code in Link that uses the URL:
https://git.drupalcode.org/project/drupal/-/blob/9.2.x/core/lib/Drupal/C...
It seems like that might be possible. We'd need to do it in a separate issue (this issue needs to be pure Help Topics Experimental and not mix in other Core changes)... But yeah, I guess we don't have to use a Link render array. I'll work on a patch for that. Thanks for the suggestions!
Comment #92
jhodgdonUgh. LinkGenerator also only works with Url objects, not with GeneratedUrl objects.
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Utility%2...
So... ???
Comment #93
jhodgdonI've had a few discussions in Slack with fabianx and others. I decided the best way to go was to write a Functional test. So, I added some parts to the existing HelpTopicsTest to test making links with:
- Invalid routes
- Missing route parameters
- Invalid route parameters
- No access
- Valid routes/parameters
- Link to a missing topic
- Link to a valid topic
that all of these work. The test found some bugs in the code too (hooray for testing!). So, here's a new patch that now has a test.
So far it only fixes 1 non-test help topic to use the new functions, which keeps the patch small and reduces the need to redo the patch whenever new topics are committed. I propose we leave this patch doing that, and follow up with a separate issue to fix all the other topics. Adding this follow-up to the issue summary (which already had a follow-up for verifying we are using the new functions exclusively).
Comment #94
daffie commentedThe patch looks good. Just one nitpick, the patch is failing the testbot and the followup still needs be be created.
Nitpick: Could we put these in the same order as this list is in other places.
Comment #95
ravi.shankar commentedFixed testbot fails of patch #93.
Still need works for comment #94.
Comment #96
daffie commentedThe correct order is:
Comment #97
jhodgdonGood idea. Here's an updated patch.
I'm waiting on creating the follow-up issues until this is RTBC, because this issue has gone through several iterations on its ideas, and I don't want to keep redoing the followups.
Comment #98
daffie commentedMy nitpick is fixed.
All code changes look good to me.
@jhodgdon has promised to create the followup after the issue is set to RTBC.
I would like to ask the committer if he/she thinks that it is OK that the chosen solution is only for help_topics or should be made more generic, so that it can also be used by other modules.
For me it is RTBC.
Comment #99
jhodgdonThanks for the review!
Adding similar things to Core outside of Help Topics would need to be a separate issue, because Help Topics is an experimental module and we cannot mix issues between Experimental and Stable parts of Core. This was a specific need for help topics twig files and I don't think it's necessarily applicable to other templates, which tend not to have a lot of content in them like Topics do.
This issue has been under review by several other people. I'm going to give them a chance to object before I create the followup issues. They could also be created after the commit. The last time this was RTBC, a committer put it back to Needs Work and we totally changed the approach... so I would prefer to know this is stable and really ready to commit before wasting effort creating follow-up issues. Don't worry, it will really happen.
Comment #100
catchThis needs both a title and issue summary update, also a change record. I haven't patch yet but in favour of the new approach.
Comment #101
jhodgdonSorry about that! Updating issue summary & title, and adding change record: https://www.drupal.org/node/3192582
I also added the follow-up issue. #3192585: Fix up topics to use new help_topic_link function
Guess this can go back to RTBC.
Comment #103
catchI think we need an explicit follow-up added for this, might need to be postponed on more conversions?
Otherwise this looks good now.
Committed 5a95baa and pushed to 9.2.x. Thanks!
Comment #104
jhodgdonThe follow-up issue that was created earlier already includes that: #3192585: Fix up topics to use new help_topic_link function
I will un-postpone it now. Thanks for committing!
Comment #106
jhodgdonI spun off the tests into their own issue: #3219923: Add tests to enforce correct use of help_topic_link and help_route_link functions
And by the way, we now have two spin-off issues to use the two functions:
#3215784: [META] Fix up topics to use new help_route_link function and #3192585: Fix up topics to use new help_topic_link function
Comment #107
amber himes matzJust adding a handy link to the change record to the issue summary (under API changes) since the link to it is buried in a comment.