Quantcast
Viewing all articles
Browse latest Browse all 293641

Extend Cacheable/RedirectResponse constructor to accept GeneratedUrl

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


Viewing all articles
Browse latest Browse all 293641

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>