Instead of only allowing one hard-coded function to rewrite outbound links, I propose we introduce a new hook (hook_url_alter) so that modules can alter the URLs processed by url() and l(). I had the need for this feature in one of my D6 modules where I wanted to rewrite the links to internal Drupal RSS feeds to a FeedBurner feed. As a part of this, I'll probably need to write a test or two, as well as do some performance testing. This could probably help move language_url_rewrite() from language.inc into locale.module.

Comments

dave reid’s picture

Status: Active » Needs review
StatusFileSize
new6.91 KB

Initial patch for review.

dave reid’s picture

Revised patch that actually works. Here's the benchmarks running ab -c 5 -n 1000 http://mysql.drupalhead.local with 50 nodes, 5 comments per node, and the recent blog posts block enabled:

w/o patch w/o locale module enabled

Requests per second:    5.20 [#/sec] (mean)
Time per request:       961.254 [ms] (mean)
Time per request:       192.251 [ms] (mean, across all concurrent requests)
Transfer rate:          78.21 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   2.0      0      32
Processing:   539  959 123.4    949    2075
Waiting:      502  883 117.4    875    1916
Total:        539  959 123.5    949    2075



w/o patch w/ locale module enabled

Requests per second:    5.05 [#/sec] (mean)
Time per request:       991.042 [ms] (mean)
Time per request:       198.208 [ms] (mean, across all concurrent requests)
Transfer rate:          75.85 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   2.1      0      33
Processing:   570  989 159.4    967    2180
Waiting:      552  911 152.6    891    2063
Total:        570  989 159.4    967    2180



w/ patch w/o locale module enabled

Requests per second:    5.17 [#/sec] (mean)
Time per request:       967.278 [ms] (mean)
Time per request:       193.456 [ms] (mean, across all concurrent requests)
Transfer rate:          77.72 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.9      0      30
Processing:   525  966 120.7    954    2030
Waiting:      513  890 116.3    883    1899
Total:        525  966 120.8    954    2030



w/ patch w/ locale module enabled

Requests per second:    5.07 [#/sec] (mean)
Time per request:       986.513 [ms] (mean)
Time per request:       197.303 [ms] (mean, across all concurrent requests)
Transfer rate:          76.20 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.8      0      29
Processing:   426  985 122.0    974    2048
Waiting:      413  906 118.2    899    1908
Total:        426  985 122.0    974    2048

About a +/- 1 ms difference with the patch. Maximum benefit is with the patch and locale module enabled.

dave reid’s picture

StatusFileSize
new8.19 KB

Revised patch used in #2.

dave reid’s picture

StatusFileSize
new7 KB

Ok, another attempt to post the patch actually used in #2.

dave reid’s picture

Title: Replace custom_url_rewrite_outbound() with new hook_url_alter() » Replace custom_url_rewrite_outbound() and language_url_rewrite() with new hook_url_alter()
dave reid’s picture

Issue tags: +hooks, +url
agentrickard’s picture

Dave, I had this issue in a module as well, and had a similar patch at one time. However, my understanding is that we need the hardcoded functions due to situations where calls to paths or translations are made early in the bootstrap process, before all modules are loaded.

Does the new code registry mean that hook_url_alter() implementations are always present when the hook is fired? I am trying to think of an example case; hopefully someone else will recall why custom_url_rewrite_*() originally had to be loaded in setttings.php.

dave reid’s picture

Well, after my initial investigations, the url() and l() functions are in common.inc, which is only included on a full bootstrap. Therefore, with the registry loader in module_invoke_all(), any hook_url_alter() implementations will be available as well. They would be available no matter the bootstrap setting anyway thanks to the registry.

lilou’s picture

Issue tags: +Needs tests
dave reid’s picture

Dave Cohen’s picture

Status: Needs review » Needs work

I would like to see the call to custom_url_rewrite_outbound() remain unchanged. That is, leave these lines intact:

  if (function_exists('custom_url_rewrite_outbound')) {
    // Modules may alter outbound links by reference.
    custom_url_rewrite_outbound($path, $options, $original_path);
  }

My feeling is that if custom_url_rewrite_inbound() is still necessary (and it is!), and quite often the two custom_url_rewrite functions have essentially the opposite effect. So there's an easy to understand symmetry and logic to having the two functions as a pair.

What you're suggesting instead is to have custom_url_rewrite_inbound() defined in my settings.php file, and have a corresponding hook_url_alter found in some module somewhere else and using a different technique to change paths. That sounds harder to maintain to me, and potentially requires a whole module where previously just a function would suffice.

I am +1 in favor of introducing hook_url_alter. And I'm -1 opposed to getting rid of custom_url_rewrite_outbound.

dave reid’s picture

Status: Needs work » Closed (duplicate)

Well...I can't claim this original idea anymore. Marking as a duplicate of #320331: Turn custom_url_rewrite_inbound and custom_url_rewrite_outbound into hooks.

dave reid’s picture

@Dave Cohen - The current implementation is a hack. If we have a chance to change things and do them the "Drupal way" we should. It will improve performance and make things easier for more than one module/etc to alter the outbound urls. It doesn't take much effort to write one small little module that would implement hook_url_alter().