After three separated attempts of analyzing the Url code and reading the related Lullabot article... I think I have a handle on why just creating a Trusted/LocalRedirectResponse with a URL is generating a LogicException.
Armed with that newfound knowledge, I wanted to make two suggestions to improve DX.
A) improve method docs of Url::toString() to warn people more clearly about what is going on - but after finding #2735575: Make Url::toString(TRUE) explicit by having a Url::generate() method, as well as having GeneratedUrl::toString I'll delay arguing for that.
B) change the first argument to the Trusted/LocalRedirectResponse constructor from a 'string' to a 'string|\Drupal\Core\GeneratedUrl' (which is equal to what UrlGenerator::generateFromRoute() returns).
(or change CacheableResponse constructor? See below.)
Problem/Motivation
1 - As far as I know, it's dangerous (can lead to hard to trace bugs) to not add cacheability metadata into a response object; this is also the case for RedirectResponse objects in principle. I'm still not 100% certain if this statement is true, so please set me straight if it isn't.
2 - The current code structure leads people in the direction of forgetting to add the metadata, or not even knowing about this.
Say, I'm a simple contrib module developer. I have a route where I just want to do a quick thing and then issue a redirect, directly in my Controller, for some reason.
- I look around for a response object and find LocalRedirectResponse.
- It accepts a string.
- I also see a Url object, which looks a bit daunting to me, but it has a toString(). This says something about bubbling metadata but I have no clue what that means and the code is impenetrable, so I ignore it in the end. (Note it doesn't say anything about the fact that unless I pass TRUE here, I could be causing caching-related bugs this way. The character string "cach" occurs zero times in the Url class.)
- So, great. I make a URL through Url::generateFromRoute()->toString() and pass it inty my response.
- BOOM! LogicException.
- Reading Url related code just makes me feel lost.
- Web searches tell me to just do Url::generateFromRoute()->toString(TRUE)->getGeneratedUrl(), as per e.g. https://drupal.stackexchange.com/questions/187086/trustedresponseredirec... / #2630808-16: Response::getResponse() does not collect cacheability metadata from Url object
- I never find out that this is the wrong advice around totally ignoring cache metadata.
I later find out that what I should have done is (Copypaste from https://www.lullabot.com/articles/early-rendering-a-lesson-in-debugging-...):
$url = $node->toUrl()->toString(TRUE);
// The generated URL string, as before.
$url_string = $url->getGeneratedUrl();
// Add the $url object as a dependency of [ the response ]
$response = new CacheableResponse($url_string, Response::HTTP_OK);
$response->addCacheableDependency($url);
Proposed resolution
We can help people prevent creating obscure bugs / not promoting flawed practices by making the following equivalent possible / hiding the parts of cacheability that they don't need to learn about if they just want to redirect somewhere:
$url = $node->toUrl()->toString(TRUE);
$response = new CacheableResponse($url, Response::HTTP_OK);
(Hmm... I now see that means we need to override the CacheableResponse constructor for this example to work, which is... a bit icky, but AFAICS it's worth it.)
Remaining tasks
You: Tell me if it makes sense (or provide a patch if you feel like it)
Me: Provide a patch.
User interface changes
None.
API changes
The above.
Data model changes
None.
Release notes snippet
TBD