After searching the forums/handbook/google for a best practice on grabbing the current URL, I finally resorted to #drupal IRC and was told that it's $_GET['q'].

There should be either a global variable (in the tradition of $base_url) or a wrapper function to return the current url. I'm voting for a wrapper function, so I'd like to make one.

Comments

webchick’s picture

Issue tags: +Bikeshed, +DrupalWTF, +Novice

I've seen this come up repeatedly as a DrupalWTF, so I would like to see this fixed, too. The question is, what to call this function so people will actually find it?

We kicked around some about naming conventions in #drupal. Since $base_url refers to something with http://... in it, current_url() would probably be confusing if it only referred to the 'node/12' part. Quicksketch suggested current_path instead, since elsewhere we refer to something like node/12 as a path. I like that better, for sure.

Adding the appropriate tags. ;)

mcrittenden’s picture

Status: Active » Needs review
StatusFileSize
new679 bytes

Here's a first attempt.

webchick’s picture

Status: Needs review » Needs work

The coding standards (know them, love them, memorize them, and buy them a nice Easter dinner to tell them how much you appreciate their awesomeness) dictate indentation should be 2 spaces rather than tabs.

Additionally, I think the PHPDoc is not quite sufficient to explain to someone who was paging through the huge list of functions how they would know that this was the one that did what they want. How about adding an example?

mcrittenden’s picture

Status: Needs work » Needs review
StatusFileSize
new964 bytes

Thanks webchick. Try number two:

mcrittenden’s picture

Alternatively, the function could prefix a forward slash onto the return var so that a complete URL can be built using base_url() + current_url()?

damien tournoud’s picture

The corresponding setter is named menu_set_active_item(). We probably should harmonize the two.

mcrittenden’s picture

FWIW, I'm opposed to renaming the patch's function to something like menu_get_active_item, just because current_path is more self explanatory and continues the tradition of base_path. If they must be harmonized, I'd rename menu_set_active_item before I'd rename the patch's function. Just my 2 cents.

damien tournoud’s picture

I agree that menu_set_active_item() is an horrible name. I'm just calling for harmonization.

mcrittenden’s picture

Rename menu_set_active_item to set_current_path then?

mcrittenden’s picture

On second thought, that's probably not a good solution either as menu_set_active_item relates to menu_set_item and menu_set_active_trail.

moshe weitzman’s picture

We don't have to harmonize right now in this issue. Thats just gonna drag down an otherwise useful patch.

Why would be bother with a tag called Bikeshed? Silly tags like this really do add rows to term_data and term_node. And then the parrots keep on re-using the tag everywhere this adding more rows and even generating email notificaitons. The silly tags make tag browsing harder and vocab admin harder. IMO, the benefit does not outweigh the cost.

mcrittenden’s picture

Title: Wrapper function for current url (i.e., $_GET['q']) » Add wrapper function for current url (i.e., $_GET['q'])
dave reid’s picture

Interesting idea. Subscribing.

chx’s picture

Status: Needs review » Needs work

Your example 2 is wrong, please note:

    $base_path = $parts['path'] . '/';

base_path always ends with a slash.

mcrittenden’s picture

StatusFileSize
new963 bytes

Here's a reroll per chx's comment. Also changed yoursite.com to example.com per coding standards.

mcrittenden’s picture

Status: Needs work » Needs review

Another reroll to fix indentation on comments. Sorry guys.

mcrittenden’s picture

StatusFileSize
new962 bytes

Forgot the patch. Sorry again :-/

franskuipers’s picture

review in patch review sprint.... my first one.

documentation is not ver clear: current_path: Returns the current URL path of the page being viewed.
In a.d.o I found:
base_path(): Returns the base URL path of the Drupal installation. At the very least, this will always default to /.
$basepath: The base path of the drupal installation. At least will default to /.
$base_url: The base URL of the drupal installation.
As a novice, how can I tel the difference?

Should we have a global $current_path too ??

to make the full url i would think (as a novice): $base_url + base_path() + current_path() , but that is not working when drupal is installed in a subdirectory. $base_url + '/' + current_path() is the right way now.

I feel the function name is not clear: How do I know it is the URL path?; in phpinfo() it is REQUEST_URI.

Maybe rename base_path to base_dir; base_url is ok; current_path can be base_drupal_url ?

mcrittenden’s picture

franskuipers: Thanks for the first review! I'd vote no for making a global var out of it just because it's unnecessary and would add another variable without any real benefit. Plus I'm not a big fan of global variables in general so I guess I'm biased (actually addressed that briefly in the opening comments to this issue).

Don't think base_drupal_url really fits since current_path is the path of the page CURRENTLY being viewed, and base_drupal_url sounds like something along the lines of base_url (i.e., something that will never change).

I wouldn't be totally opposed to the idea of renaming base_path to base_dir (kind of lukewarm on that issue), but either way I think we should focus on the current_path function in this issue and introduce the prospect of renaming other functions in separate issues.

chx’s picture

I am sorry that I have not posted this in the first round -- sorry that was a quick attempt to just CNW it and then return if the author still loves her/his patch. Apparently does, thanks!

So, the problem is with path aliases. If you have 'path/alias' as an alias for 'node/123' and you browse to example.com/drupal/path/alias then this function returns node/123 once you are past DRUPAL_BOOTSTRAP_PATH -- but hook_boot fires before that...

mcrittenden’s picture

chx: pardon my newbishness. I don't understand why calling a function which calls $_GET['q'] is any different than calling $_GET['q'] directly as far as what it returns. In IRC you referenced http://api.drupal.org/api/function/drupal_init_path/7 which calls http://api.drupal.org/api/function/drupal_get_normal_path/7 which then calls http://api.drupal.org/api/function/drupal_lookup_path/7 which finally sets $_GET['q'] to the path alias rather than the node/XXX path, and that all makes sense. I just don't understand why all that won't happen when called inside a wrapper function as well.

Thought I'd post here instead of IRC so that others could benefit/contribute.

chx’s picture

It is not different. $_GET['q'] is undocumented. And this function is documented. What I asked for is "simply" updating the documentation.

chx’s picture

StatusFileSize
new1.87 KB
chx’s picture

Note that I have moved the function to path.inc where it belongs and added comments about path aliases and bootstrap phases.

caktux’s picture

StatusFileSize
new1.39 KB

Some typo and syntax fixes :)

caktux’s picture

StatusFileSize
new1.4 KB

Syntax fix from chx, ready for commit I think ;)

mcrittenden’s picture

StatusFileSize
new3.24 KB

Per IRC request of chx and others, here's an updated version which includes tests. Note that this necessarily includes the addition of a new test file (path.test).

franskuipers’s picture

Status: Needs review » Reviewed & tested by the community

Documentation awful good.
Simple 3 lines code, tested it (with devel PHP execute).
Simpletests passes.

I think: ready to commit.

caktux’s picture

cburschka’s picture

Status: Reviewed & tested by the community » Needs work

Excellent patch! Throughout, I could find only code-style and commenting problems.

+ 
+/**
+ * Returns the current URL path of the page being viewed.
+ *

The first blank line in this chunk contains trailing white-space.

would return

The hypothetical form seems unnecessarily cumbersome here. "When viewing ..., this function returns ..." would be-- sorry, /is/ more straight-forward. I also think "return "node/306", while base_path() would return" sounds better than " and base_path() would return"...

+ * Example #3: When viewing "http://example.com/path/alias" and is a path
+ * alias for "http://example.com/node/306", then on viewing
+ * "http://example.com/path/alias", this function would still return
+ * "node/306".

Needs to be fixed so that grammar and redundancy are fixed. :)

+  public static function getInfo() {
+    return array (
+      'name'=>t('Path'),
+      'description'=>t('Test overall functionality of the path system.'),
+      'group'=>t('Path'),
+    );
+  }

Spaces required on either side of the "=>" operator.

+  /**
+   * Test integrity of current_path() function
+   */
+  function testCurrentPath() {
+    // Initialize series of comparisons between current_path and $_GET['q'] for various paths
+    $_GET['q'] = "/";
+    $this->assertEqual(current_path(), $_GET['q'], t('Test integrity of current_path() compared with backslash'));
+    $_GET['q'] = "";
+    $this->assertEqual(current_path(), $_GET['q'], t('Test integrity of current_path() compared with empty string'));
+    $_GET['q'] = "node/".rand(5, 15);
+    $this->assertEqual(current_path(), $_GET['q'], t('Test integrity of current_path() compared with random node path'));
+
+    // Generate a random string for comparison
+    $rand_str = "";
+    $possible = "0123456789bcdfghjkmnpqrstvwxyz";

1.) Comments need to end in a period and form complete sentences. (It couldn't hurt to do the same for the assertion messages, though I don't know if it's required there.)
2.) Strings are always encapsulated by single quotes, unless they contain variables, \n-escaped line-breaks, or apostrophes.
3.) String concatenations require a space on either side of the dot.

+      $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);

The minus operator also needs spaces on either side.

+  }
+
+}
+

The first of these blank lines should be removed. I don't know about the second one.

chx’s picture

we have $this->randomname for random strings. Probably just one test against a random string is enough?

Pedro Lozano’s picture

Shouldn't all references to $_GET['q'] be converted to current_path() ?

If you do that in this or another patch, can sentences like these be converted without problem with the current patch?

common.inc

$path = isset($_GET['q']) ? $_GET['q'] : '';

language.inc:

$args = isset($_GET['q']) ? explode('/', $_GET['q']) : array();
mcrittenden’s picture

Pedro Lozano: Yep, that shouldn't cause any problems. If and when it's done, though, I'd vote to stick it in another issue so it doesn't weigh this one down.

I'll reroll a patch in response to the reviews above ASAP.

mcrittenden’s picture

Status: Needs work » Needs review
StatusFileSize
new2.82 KB

Updated patch to reflect chx's "randomName()" function and Arancaytar's grammar and coding style problems.

mcrittenden’s picture

StatusFileSize
new2.83 KB

Discovered a couple more minor commenting problems. Let's try this again:

mcrittenden’s picture

Issue tags: +path, +Drupal core functions, +path.inc

Tagging.

cburschka’s picture

Status: Needs review » Needs work

Just one more quibble from me:

+ * Example #2: On viewing http://example.com/drupalfolder/node/306 this
+ * function returns "node/306" while base_path() returns "/drupalfolder/".
+ *
+ * Example #3: On viewing "http://example.com/path/alias" which is a path
+ * alias for "http://example.com/node/306", this function returns "node/306" 
+ * as opposed to the path alias.

You can either quote the URLs or not, but it should be consistent. :)

Okay, two quibbles:

+    $_GET['q'] = $this->randomName(); // Set $_GET['q'] to a random string for comparison.	

Comments should be on a separate line immediately before the code they reference.

That's really all I can see now.

mcrittenden’s picture

StatusFileSize
new2.84 KB

Thanks for your reviews Arancaytar. Here's an updated patch per your two comments.

mcrittenden’s picture

Status: Needs work » Needs review
cburschka’s picture

+    // Set $_GET['q'] to a random string for comparison.	|
+    $_GET['q'] = $this->randomName(); |

Whoops, some whitespace left over at the end of these lines. But this is really the last thing!

mcrittenden’s picture

StatusFileSize
new2.84 KB

White space fixed. Thanks again.

mcrittenden’s picture

Category: feature » task

Probably not really a feature request.

cburschka’s picture

Status: Needs review » Reviewed & tested by the community

This looks great now!

The new path.test will need some further test cases (for alias resolution and the like), but this part of it is ready, I believe.

webchick’s picture

Status: Reviewed & tested by the community » Needs work

A couple very minor things. Once they're fixed, please mark back to RTBC. mcrittenden, you've earned the title of "Trooper Of The Year." ;)

+class PathsTestCase extends DrupalWebTestCase {

This is missing a PHPDoc declaration on this class.

+  /**
+   * Implementation of getInfo().
+   */

Because this a) is not a hook, and b) is inherited from DrupalWebTestCase, we actually do not document it. Strange but true. So this chunk can be removed.

+    // Set $_GET['q'] to a random string for comparison.
+    $_GET['q'] = $this->randomName(); 
+    $this->assertEqual(current_path(), $_GET['q'], t('Test integrity of current_path() compared with random string path'));

The newly added $this->randomString(); is probably more appropriate here, as that's truly a random string, not a random set of garbled characters.

webchick’s picture

Oh, incidentally, if there is still some documentation somewhere telling you to do it like this, please correct it.

cburschka’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new2.75 KB

Since the remainder is really trivial and I have a moment, I've made the changes. Don't bother crediting me. ;)

sun’s picture

Status: Reviewed & tested by the community » Needs work

Instead of duplicating content, I'm pointing to the same review remarks in #432864: Improve comments for function base_path(), which identically apply to this patch.

In general though, I'm a bit opposed to this patch. We have a lot of - senseless - function invocations to base_path() in core and contributed modules. Invoking a function just to get the value of a variable that is available directly is nonsense.

base_path() may be "more special" here, because it returns the value of a global variable. However, $_GET['q'] is... well... a standard environment variable. Accessing it via a function makes absolutely no sense to me. That's plain overhead.

So, if we add this function at all, then only as a helper function for n00bs that don't understand PHP. The PHPDoc should make that purpose clear, and that "regular" PHP coders do not need to resp. should not use it.

sun’s picture

And - sorry, mcrittenden, your effort is great and this is not targeted to you...:

RTBC...? The tests are nonsense. These are testing PHP, not Drupal.

If at all, http://api.drupal.org/api/function/drupal_init_path/7 would have to be used for comparison.

moshe weitzman’s picture

Status: Needs work » Reviewed & tested by the community

No, it isn't senseless. This consolidates code so that we can make future changes in one place. Further, this makes code more readable. $_GET['q'] is a DrupalWTF that means nothing. current_path() is much more descriptive. And I don't really know where to begin with the suggestion that we add phpdoc that says that noobs should use this function but others should not.

The committers can decide whether this needs work or not.

sun’s picture

Status: Reviewed & tested by the community » Needs work

Issues with PHPDoc and test comparison still remain.

webchick’s picture

I disagree completely that this is for "PHP n00bs." This is a DX issue. People with clean URLs enabled (which is the default) have absolutely no idea that there is a ?q=xxx in there, and unless they make a regular habit of var_dump($_GET);ing as they're developing (which, who does?) they end up in #drupal asking the question, "How do I get my current path?", which usually occurs about 3-4 times per week.

It's a nice convenience function for developers, with a negligible performance impact.

webchick’s picture

I do agree, however, that the PHPDoc of this function should be re-worked to match that of the committed base_path() function. That one was off my radar, so thanks for pointing that out.

And yeah, actually. The tests should be higher-level to cover possible future changes in how we determine what the current path is, as Moshe pointed out. So maybe something like drupalGet(''), check to make sure the current_path() returns ''. Create a node with a path alias, ensure that current_path() still returns node/$nid.

mcrittenden’s picture

sun: don't worry about offending me. I understand that I'm still new at this and the more constructive criticism I can get, the better. :)

I'm of course fine with fixing comments and I'll do that ASAP (probably Monday if not sooner). But I don't agree that tests here need to be more high level in this specific patch. This patch returns q out of the get array, and nothing more. Therefore, the tests just make sure that it is really returning the q value out of the get array.

I agree that tests need to be put in place eventually to make sure that that q value is what it's supposed to be (i.e., webchick's suggestion with creating a node and alias), but that is completely out of the scope of this patch.

I don't think a simple wrapper function even really warrants a test to begin with because as sun said, all it's really doing is testing PHP, but chx and davereid agreed in IRC that it's needed, no matter how trivial (in fact, the idea of comparing the function's return value to a random value of get q was chx's suggestion...might be interesting to hear his thoughts on this).

I'd vote to fix the comments and get this in there, and devote another patch to testing the paths/alias system in general.

That being said, again I know that I'm new at this and might be completely off base or ignorant. So if/when I'm overruled I'll be happy to fix the tests. :-D

P.S. Sorry for typing out get array...I'm on my phone and brackets are a pain. :)

cburschka’s picture

The point here is that the function itself is trivial and needs no exhaustive testing, but the path handling in total is completely lacking a test suite.

There are at this point two ways we can go:

1.) Decide that the function is trivial enough to need no test in itself, and leave the whole path.test for a separate issue.
2.) Decide to put in a trivial test case for this function.

I agree that we desperately need path.inc tests, and eg. check drupalGet('') -> '', or drupalGet('content/title-alias') -> 'node/123'. But if we do that here, this patch would lose focus from a trivial function addition and become a test suite for path.inc instead, and that should be avoided. Think of the kittens. ;)

Edit: Here we have a bit of a refactoring WTF, because obviously there is also path.module, and while alias resolution is actually done in path.inc, it is tested by modules/path/path.test, so the tests for path.inc don't need to duplicate that. But still, there are plenty of other parts of path.inc that do need tests.

damien tournoud’s picture

I agree on removing the tests here (those serve no purpose).

mcrittenden’s picture

Status: Needs work » Needs review
StatusFileSize
new1.2 KB

Fixed comments and removed all tests. More opinions on the testing debate are welcome.

mcrittenden’s picture

StatusFileSize
new1.19 KB

Fixed typo.

sun’s picture

Status: Needs review » Needs work
+ * This function is not available in hook_boot; use $_GET['q'] instead. Also, be
+ * careful in the case of Example #3 if you use it in hook_boot as it
+ * will contain "path/alias". Calling drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH)
+ * makes this function available with a return value of "node/306".

When referring to function names and hooks, append trailing braces (hook_boot()).

The description is a bit contradictory - first you say it's not possible to invoke it in hook_boot(), then you explain the return value when used in hook_boot().

We should not teach developers to manually invoke drupal_bootstrap() during the bootstrap process. We already have some contrib modules that do this without any good reason.

mcrittenden’s picture

StatusFileSize
new1.19 KB

That contradiction was because of someone trying to fix chx's grammar above and ending up changing the meaning completely. Fixed that and appended trailing braces. I don't want to remove the mention of drupal_bootstrap() until chx takes a look at it. It was his comment, so he should get to respond.

mcrittenden’s picture

Status: Needs work » Needs review
StatusFileSize
new1.19 KB

Oops, couple whitespace fixes.

chx’s picture

Edit: nevermind. The change I wanted is incorporated in #60 already.

mcrittenden’s picture

What? :)

chx’s picture

Status: Needs review » Reviewed & tested by the community

I think this is good. Its the role of hook_boot to tell people "this is not the hook you are looking for"...

dries’s picture

Status: Reviewed & tested by the community » Fixed

Committed to CVS HEAD. Thanks. I've decided not to commit the tests, we can revisit that if desired.

mikeytown2’s picture

Heads up from doing boost dev; i18n support with $_GET['q'] isn't all there because of http://api.drupal.org/api/function/drupal_init_path. Our solution was to use $_REQUEST['q']. This is an edge case, just thought I would let you guys know.

sun’s picture

@mikeytown2: That has always been the case and probably won't change anytime soon. The language prefix is a "virtual" path component - prepended by url() when links are generated, removed by drupal_init_path() when $_GET['q'] is rebuilt. Virtual path prefixes only exist for the language system currently, but people (like me) already considered to re-use this approach to build site sections/contexts (think OG/Domain Access) by adding further prefixes to paths. Also note that $_REQUEST['q'] is always the unaltered 'q' query argument value, very potentially containing an URL alias, not an internal Drupal path. These are further reasons why $_GET['q']/$_REQUEST['q'] is almost unusable prior DRUPAL_BOOTSTRAP_PATH.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

mcrittenden’s picture

Sorry to bring up an old issue, just wanted to ping everybody on #653510: Replace $_GET['q'] with current_path() throughout core.