I've had a problem with nested template files taking precedence over a non-nested file. In my specific case, I have a sub-theme's breadcrumb.tpl.php file being used in place of a base theme when the base theme is the one that's enabled. The problem appears to lie in the file_scan_directory(); function.
When file_scan_directory(); is called in relation to the theme, it returns all files and directories in alphabetical order. Since this goes through things alphabetically AND recursively, any template files that are in directories named after the name of the template file will always replace the the parent theme's template file.
If a print was done in the loop in file_scan_directory(); to display the $dir/$file for a sample "base" theme, here's what it might look like:
base/.
base/..
base/base.info
base/breadcrumb.tpl.php
base/node.tpl.php
base/style.css
base/sub_theme
base/sub_theme/
base/sub_theme/.
base/sub_theme/..
base/sub_theme/breadcrumb.tpl.php
base/sub_theme/style.css
base/sub_theme/sub_theme.info
base/template.php
So in this example, when the "base" theme is enabled, the file base/sub_theme/breadcrumb.tpl.php will be used because it was found last. While this might be desired functionality elsewhere, it will certainly be troublesome for theme developers.
| Comment | File | Size | Author |
|---|---|---|---|
| #22 | file_scan_directory_fix_with_comments_2.patch | 1.02 KB | fractile81 |
| #20 | file_scan_directory_fix_with_comments.patch | 1016 bytes | fractile81 |
| #13 | file_scan_directory_fix.patch | 733 bytes | fractile81 |
| #2 | sort_file_scan-173664-2.patch | 546 bytes | chx |
Comments
Comment #1
fractile81 commentedSeeing that a beta version just came out, and thinking about the implications of this bug, I really want to make sure it has been addressed before Drupal 6 goes prime-time. If you need any further clarification, please let me know.
Comment #2
chx commentedActually, it's not ABC sorting it's whatever you have in your hard drive -- nor file_scan_directory nor drupal_system_listing sorts. That's the bug.
Comment #3
fractile81 commentedThank you for looking into this. I tried your patch on my pre-beta copy of Drupal 6, and it didn't fix the problem. I then updated to Drupal6-beta1 and the patch still didn't work (the patch even broke Drupal when I reinstalled the database because the
$filevariable in the loop is an object now).If this helps any, I'm running Drupal under Windows and Apache in PHP 5.2. When a directory is traversed using
opendir();andreaddir();, they are being returned in alphabetical order for me.I went back and tried to get this to work, and it did after making the following modifications to the
file_scan_directory();function in includes/file.inc:877 :I've changed it to only overwrite the
$filesindex if it is closer to the base directory. If two files are the same depth away from the base directory, the first one encountered will take priority. I'm not sure if this is the best way to do it, but it does fix the bug.Hope that helps explain my problem a little better.
Comment #4
fractile81 commentedI just revisited the problem I was having, and realized that the real issue is that files from the recursive call to the
file_scan_directory();function were overwriting anything set in the callingfile_scan_directory();. A simple change to line includes/file.inc:885 fixes the problem without the extra logic:All I did was move the
$filesvariable to be the second argument rather than the first. This basically does the same thing as my previous code posting without the added logic, giving priority to files found closer to the base directory or found first. The only problem with this is that if a file isn't found in the base directory, the first time it is found in a recursive call would take priority over something that might be closer (e.g../a/b/c/example.tpl.phpwould be chosen over./z/example.tpl.php). I'm uncertain as to whether that would be a problem or not. The alternative would be to do the depth checking instead of thearray_merge();.Again, I'm still uncertain as to what other functionality might be impacted by this change, but it does fix the sub-theme problem I originally outlined.
Comment #5
fractile81 commentedIs anyone else able to confirm this as a bug?
Comment #6
andremolnar commentedCould not reproduce this problem.
Created sub theme with a single modified page.tpl.php file. Changed theme to subtheme - correct template file was loaded from subtheme. Changed back to base theme - correct template file was loaded from base theme.
Comment #7
fractile81 commentedDid the sub-theme directory's name come alphabetically after the letter P (name of the template file)? My problem is that:
would work fine because the base
page.tpl.phpwould be the last found file. However:would break, using the sub_theme's template file since it would be the last occurrence of
page.tpl.php. Could you verify this and follow-up? I really appreciate this sanity check!Also, just out of curiosity, what platform are you testing this on?
Comment #8
fractile81 commentedAs an aside, make sure you clear your cache when you make the changes since the template files used are now being cached. I know I've forgotten to do this a couple times myself.
Comment #9
andremolnar commentedCan't reproduce:
tried two sub-themes:
themes/garland/page.tpl.php
themes/garland/gapland/page.tpl.php
^
themes/garland/page.tpl.php
themes/garland/arland/page.tpl.php
^
Cleared cache. Always had correct template display.
Comment #10
fractile81 commentedTry renaming your sub-theme directory to something like "zed" and see what you get. The key is that the sub-theme's directory name must come alphabetically AFTER the name of the template file. Both "gapland" and "arland" would be hit before page.tpl.php because they start with letters before the letter P, and thus there are no problems.
I'll see if I can't also reproduce this on a different server setup myself, but if you could try the above out, that would be great! If you can reproduce the problem, see if the solution in #4 fixes it. Thanks!
Oh, and if it helps any, I'm doing this under
sites/all/themes. I'll test to see if just/themesmakes any difference.Comment #11
andremolnar commentedApologies, brain went on vacation when i created the second test case.
Yes - I see the problem.
The actual patch #2 file is broken:
Notice: Undefined offset: 4096 in E:\www\htdocs\drupal\includes\common.inc on line 574
Notice: Undefined offset: 4096 in E:\www\htdocs\drupal\includes\common.inc on line 581
: Object of class stdClass could not be converted to string in E:\www\htdocs\drupal\includes\common.inc on line 2521.
Have not tested any of the code you have pasted in. Can you produce a patch that I can test.
Comment #12
fractile81 commentedI'll see what I can do about creating a patch from the code in #4. As for patch #2, it ends up ordering file information AFTER the directories have already been traversed, which is a little late (plus it was was against a version of 6 before the beta).
I must say, I'm just glad someone else was able to reproduce this bug.
Comment #13
fractile81 commentedAttached is a patch that applies the fix mentioned in #4. This will favor a file at the base directory of the scan over one found in a subdirectory. For every matching file not in the base scan directory, the first file found will be used instead (remember that traversing a directory is done alphabetically).
I was able to confirm that this patch fixed my problem. Just make sure you flush the cache after the patch has been applied and it should work.
Comment #15
fractile81 commentedSo if the Bot has passed the patch, does that mean it has been patched into head or that it's ready to commit?
In the off-chance that it's the latter, I'll update this issue to reflect such.
Comment #16
wim leersIt means the patch can be applied successfully to HEAD. It doesn't mean the code is RTBC.
Comment #17
fractile81 commentedWell, I've tested this patch and it both works for me and fixes the bug. If anyone else can put eyes on this, that'd be appreciated!
Comment #18
andremolnar commentedTested - works as advertised - code change simply changes the order of the arguments in the array merge - as a result you get the expected return value.
Another set of eyes would be helpful to ensure no other code is expecting the original 'wrong' behaviour from this function
Comment #19
gábor hojtsyBecause this precedence issue is tricky, let's document this in a comment above the array_merge()!
Comment #20
fractile81 commentedI've added comments to explain what is happening with the file-matching code in this function. Nothing else has changed.
Comment #21
gábor hojtsyHm, your code comments don't seem to be right for the default invocation case for this function for example...
Well, the array_merge() adds what comes from the subdirectory, BUT then overwrites it again with what was in the parent directory, if there are equal indexes. But then whether there are equal indexes possible or not at all depends on the value of the $key param. If it is "filename", then equal indexes are not possible at all. If it is "basename", then equal indexes are possible (and even likely with subthemes in subfolders).
I would do something like:
The double $$ on the key is intentional, and is evident why by looking at the code bellow.
Comment #22
fractile81 commentedChanged the wording of the first comment a little and just copied the other comment suggestion you made.
Comment #23
fractile81 commentedUpdating the status. Since there's no functional changes from when this was RTBC before the comments, this patch should do the trick.
Comment #24
fractile81 commentedIs there anything else that needs to be done for this to be committed? This is a really simple bug fix that will save themers grief down the road. The patch is in #22.
Comment #25
gábor hojtsyWe just did not have the time to look into this patch. Now committed, thanks.
Comment #26
(not verified) commentedAutomatically closed -- issue fixed for two weeks with no activity.