Posted by chx on May 13, 2006 at 7:05pm
19 followers
| Project: | Drupal core |
| Version: | 8.x-dev |
| Component: | base system |
| Category: | task |
| Priority: | normal |
| Assigned: | chx |
| Status: | needs work |
Issue Summary
Making it default to TRUE would be safest but might require quite a bit of code to be patched. Certainly, I can live with that. It also mandates that we stop using $_GET['q'] and that we run everything through arg().
Dries, usually I fulfill your requests much faster, this particular one took off only after a year you have written about it, but still, here it is. The $_GET['q'] part is not yet done but that's piece of cake.
| Attachment | Size | Status | Test result | Operations |
|---|---|---|---|---|
| arg_0.patch | 31.43 KB | Idle | FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch arg_0.patch. | View details | Re-test |
Comments
#1
Note that this is only the first step. The second will be patching menu_execute_active_handler... But first let's get this in a working shape... I guess there will be lot of things broken.
#2
Thanks for working on this, chx. It's an important feature. However, this is not 100% what I had in mind. What I had in mind was a simple (optional) "type system". For example:
<?phparg(1, 'integer');
?>
Then, the first argument would be cast to an integer. Other types could be 'raw' and 'plain' (escaped text). The 'problem' with your version is that
arg()can have various return values / types, which is confusing. I think it should always return the value. The comparison shouldn't take place inarg(), IMO.The problem is that often, people trust the return value of arg(1), which they shouldn't.
#3
Maybe we could introduce wrappers so it's less confusing?
Now that you mention plain... yep. Raw is never needed, so the attached patch would also be enough just for security.
#4
neh, the second patch is not good, for example profile uses something close to raw. I will think on it.
But I still like my solution best :)
#5
Moving to 7.x. This would be a small - yet nice feature :)
#6
@chx: can you confirm this can be closed?
#7
Not at all. There are ideas brewing about validating path parts in the new menu system.
#8
The wish for something like this harkens back to the days when I was a Drupal freshie.
We have a new menu property: mask.
mask can be a regular expression as demonstrated -- not for the faint of heart, mind you -- in taxonomy module.
In order to save people from writing regular expressions for the most common cases, we are introducing some shorthands: '+' any character, %d means a number, %c means a word character, %t means a character that can appear in a node type -- lower and upper case letters and the underscore.
What this makes this interesting is that you can also mask the parts beyond the router path. So if you have defined foo/bar then foo/bar/%d means that foo/bar and foo/bar/123 are acceptable paths here, otherwise the path will not be found. foo/bar/%t/%d means that foo/bar/article/12 is good and so is foo/bar/article. If you want to not allow foo/bar/article, never forget that you can supply a regexp yourself. %d+ means any number of numeric arguments so foo/bar/123/1243 etc are also good.
If router path is $path then "$path/+" is what currently Drupal does. Do not let the additional slash fool you: as detailed above, the parts after the router path are always optional.
#9
To clarify, node/%edit gets translated automatically to node/\d+/edit so no need to define a mask. You need a mask if your percent sign is not a positive integer or if your callback can accept arguments after the router path. The latter is automatic right now and while extermely powerful, a little validation can't hurt.
#10
After an insightful chat with chx on IRC, I'm convinced that we need the extra flexibility of this new 'mask' property.
To clarify, there is three routes hook_menu implementations might take while dealing with this new property:
The shorthand forms ease the definition of matchers for menu parts: you can use '%d', '%c' and '%t' as a menu part and the regexp will be built for you.
Obviously the code needs work (I'm not even convinced it works in its current form), but the architecture looks sane.
Oh, one more thing: I'm not convinced about the usefulness of
'%c'. What are the use cases for this? (to be clear: this will prevent any non-word characters (such as . , - etc.) to be used).#11
Could you provide some example paths from Contrib where this will be useful? There is only one instance in this patch for core. (taxonomy/term)
#12
Moshe, I am fairly sure that's not the case -- any core function that takes arguments after its router path needs a mask. Contrib... for example, you have
og/subscribe/%nodeand the callback function isfunction og_subscribe($node, $uid = NULL)the mask isog/subscribe/%d/%d. Thus the$uidis ensured to be a number. Without the mask you can not pass in a $uid. Edit: but even with the mask the $uid is not mandatory. I admit this is not 100% intuitive.Or you have
og/approve/%node/%user/%where the last percent sign is a token. its mask could beog/approve/%d/%d/[a-fA-F0-9]or a simpler, less strict mask could beog/approve/%d/%d/%c. Without the mask you can't pass in hex only numbers.Note that if you dislike copypaste then
X/X/%d/%d/%cwould do or I think the code would happily deal with even//%d/%d/%c. Edit: this is a safety belt against typos. We might say that this feature falls in the "we do not babysit broken code" category and remove it.#13
subscribing, will review later.
#14
cwgordon7 argues that using an array would be better than the paths. I tend to agree -- while in the router path we can skip the literal parts and most of the times we can also skip the wildcards as they are numeric anyways.
#15
Updated patch that removes the %t, and instead lets you define constants of the form strtoupper(placeholdername) . '_MASK' (e.g. NODE_TYPE_MASK). It will then concatenate the value of that constant into the regular expression.
Also removes an accidental menu_rebuild() from index.php.
Also adds schema definition/update functions.
Also moves a lot of the heavy work of building the mask from the array into a separate function.
Also adds a test case.
#16
After discussion with chx in irc, we agreed that the /? was insufficient. We are now using rtrim($path, '/') before checking the path, thus maintaining the old behavior of having node/1, as well as node/1/, as well as node/1///// be valid paths. Whether this behavior should continue is up to community debate.
Note that this is at code needs review because there is no architecture needs review status, there are many known bugs that can only be fixed once the new API is fully adapted throughout all modules, which we don't want to do until we have a solid, supported architecture.
#17
Updated patch posted, with better function names and removed trailing slash handling after realizing that path.inc does that for us.
#18
#17 looks all clean, good and shiny, except for that:
<?php$mask_length = max(array_keys($item['mask']));
for ($i = 0; $i <= $mask_length; $i++) {
// build $mask_part
$mask .= $prefix . $mask_part;
}
$mask = '#^'. $mask . $suffix .'$#';
?>
First it would be cleaner to have the $suffix addition moved inside the loop (to be consistent with the $prefix). Then, I think the $mask_length is wrong, it should probably be something like:
<?php$mask_length = max(array_keys($item['mask'])),max(array_keys($item['_parts']));
?>
Finally, because %d is equal to %, why not dropping it?
#19
$suffix inside the loop won't work, it's stack like. $mask1 . $mask2 . $postfix2 . $postfix1 -- if you concat $mask1 to $postfix1 how will you stick the next ones between them. % works because it was the quickest way to code a fallback but we won't really advertise this :) . %d is the consistent mask.
#20
@chx, ok drop my first and last comment from #18. What about the comment about
$mask_length?#21
That's one valid concern -- but it's a bit of an edge case so I commented it.
#22
just commenting to subscribe for now. chx and I discuessed this a few weeks ago - hopefully it can add some robustness to callback handling.
#23
A 'rest' key is supported so that you can define any number of closing arguments.
#24
fixed an edge case, added tests for 'rest', and moved the test file to the correct location
#25
Spot the bug! I know where it is and time permitting I will fix it :) but the patch is still in "architecture (needs review)". (hint. it's with the rest key)
#26
The problem was that the suffix needs to go after the rest, otherwise rest could replace the specified optional arguments. Adjusted the test too.
#27
BTW, the status would be "architecture (needs review)" if we had one like that. the patch will generate errors in head, because it's the architecture that needs review. if we like the architecture then the rest of the patch will be fixed.
#28
Patch no longer applies. (menu.test already exists)
patching file includes/menu.incHunk #5 succeeded at 2408 (offset 16 lines).
Hunk #6 succeeded at 2436 (offset 16 lines).
The next patch would create the file modules/simpletest/tests/menu.test,
which already exists! Assume -R? [n]
Apply anyway? [n] y
patching file modules/simpletest/tests/menu.test
Patch attempted to create file modules/simpletest/tests/menu.test, which already exists.
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file modules/simpletest/tests/menu.test.rej
patching file modules/system/system.install
Hunk #1 succeeded at 876 (offset -4 lines).
Hunk #2 succeeded at 3056 (offset 7 lines).
patching file modules/taxonomy/taxonomy.module
patching file modules/taxonomy/taxonomy.pages.inc
#29
#30
Keeping up with HEAD.
#31
The last submitted patch failed testing.
#32
I tried to review this but really don't feel qualified. I did notice that it is missing a patch to menu.api.php which described the new mask property.
#33
#34
The last submitted patch failed testing.
#35
#36
The last submitted patch failed testing.
#37
Reroll against HEAD.
#38
The last submitted patch failed testing.
#40
Poor testbot. I left in a menu_rebuild in index.php.
Edit: phew, caught it before cron ran so the previous comment is now deleted.
#41
Aaaaand I managed to upload the same but wrong patch. Damn.
#42
The last submitted patch failed testing.
#43
The logic was a bit broken.
#44
The last submitted patch failed testing.
#45
I just saw dblog passing without fixing. I fixed a few modules manually but dblog passed here. Let's see what else is breaking. Note that breaking is good because it signals the patch does something useful.
#46
The last submitted patch failed testing.
#47
Minor comment - we already use "mask" for a different aspect of the menu system, so that seems like a sub-optimal term for it. Maybe 'match' or 'filter' or 'expect'?
Also, this assumes people will write the regex correctly- can we maybe have an alias for using is_numeric() or have that as a default?
#48
I guess this is too big an API change for 7.x
#49
subscribe.
#50
subscribing.
#51
Here is a simple patch for 7.x and 8.x that delivers a 404 if there are extra path arguments.
#52
The last submitted patch, 63390-no-excess-args-51.patch, failed testing.
#53
ok, well that's revealing cruft in comment, forum, and other modules. This fixes some of it.
#54
The last submitted patch, 63390-no-excess-args-53.patch, failed testing.
#55
Oops - put the if in the wrong place before - hopefully this should remove most of the exceptions.
#56
The last submitted patch, 63390-no-excess-args-55.patch, failed testing.
#57
oops missed a {
#58
The last submitted patch, 63390-no-excess-args-57.patch, failed testing.
#59
subscribing
#60
We are definitely not dropping this very useful feature. Drupal 8 is already going in directions I am extremely uncomfortable with and dropping another Drupal-only, Drupal-defining feature is not in the cards.
#61
Is this really a Drupal-defining feature? It seems rather a legacy of the old menu system.
#62
I don't really feel like this is a "feature" of Drupal. @chx, can you provide some examples? Also, you went from working on this to being opposed to it. Is it pwolanin's approach or you've had a change of mind? Can you expand on your thinking?