Problem/Motivation
When called with default options, the url()
function expands aliases and will fail if invoked before Drupal has been fully installed. When modules are being installed from an install profile, their installation code may be invoked before all of the required database tables have been created. Therefore, the url()
function should not be used within any code that may be invoked from an install profile, unless its alias
parameter is set to TRUE
.
Possible resolutions
- #22
-
This limitation of the
url()
function should be documented in its function header. - #25
-
The documentation for the alias option should warn that it must be set to
TRUE
for code that may be invoked at install time. - #27
-
The alias option should automatically default to
TRUE
at install time. - #21
-
Every Drupal core function should document the possible scope(s) in which it may safely be used.
- #23
-
The install profile documentation should indicate which core functions may or may not be safely invoked at install time.
- #20
-
Relevant
hook_foo()
api documentation should indicate which core functions may or may not be safely invoked therefrom. - #32
-
Prevent alias expansion while the installer is running, regardless of the
$options['alias']
value. - #1311774
-
Use a
path.inc
replacement while the installer is running.
Remaining tasks
A consensus must be reached and acted upon.
User interface changes
None.
API changes
None.
Original report
I recently discovered that using the url()
function in a hook_requirements()
implementation will trigger the following cryptic error and abort the installation:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'd7.url_alias' doesn't exist
If this behavior is correct and by design, it should be mentioned somewhere in the documentation.
Comments
Comment #1
pillarsdotnet CreditAttribution: pillarsdotnet commentedNote that the above error only occurs if the module in question is installed through a custom profile. When installing manually, through the
admin/modules
page, there is no error.Comment #2
pillarsdotnet CreditAttribution: pillarsdotnet commentedI tried inserting the following code just before the
url()
call:The following error message aborted the installation:
Comment #3
jhodgdonSo you are saying we should document that url() cannot be used in hook_requirements()? Or is this a core code bug?
Comment #4
pillarsdotnet CreditAttribution: pillarsdotnet commentedYou can use url() in hook_requirements(), as long as your module will never be installed through an installation profile.
I don't know if the behavior is a bug or by design.
If it is a bug, then it is a core bug. If it is intentional, then it may already be documented *somewhere*.
Therefore I submitted it (first) as a documentation bug, in the hopes that if this *is* documented somewhere, then someone on the documentation team would know about it.
I expect one of the following outcomes:
Should I have submitted this as a support request? It is my experience that support requests against Drupal core get ignored.
Comment #5
jhodgdonOK, let's move this to base system, and see what they say (whether it's by design/doc issue or a core issue).
In either case, it needs to be addressed in Drupal 8 first at this point, then backported to 7.
Comment #6
pillarsdotnet CreditAttribution: pillarsdotnet commentedComment #7
pillarsdotnet CreditAttribution: pillarsdotnet commentedPosted links to this issue on both the
url()
andhook_requirements()
API pages.Comment #8
girishmuraly CreditAttribution: girishmuraly commentedRan into a similar issue before. Basically when enabling a module during installation phase (profile), most of the drupal functions are not available yet. Hence unfortunately I needed to use workarounds and more basic functions. Use the $phase argument to check for the phase you are in.
Here is an example from the superfish module:
Comment #9
apadernoDoes the error happen also when
$phase
is equal to "runtime"?Comment #10
pillarsdotnet CreditAttribution: pillarsdotnet commented@#9 by kiamlaluno on October 15, 2011 at 2:36am:
Of course not. It only happens when invoked from an install profile, in which case
$phase
would be equal to"install"
. The confusing thing is that when installing modules via the administration screens (not from a profile), the error does not occur, even though$phase
would also be equal to"install"
in such a case.I'm going to call this a documentation problem. Here's a patch.
Comment #11
pillarsdotnet CreditAttribution: pillarsdotnet commentedSummary updated.
Comment #12
jhodgdonDocumentation seems to be a reasonable course of action, and thanks for the patch!
After reading through this issue thread in some detail, though, I'm wondering if "full bootstrap" is actually the problem though. It seems like the problem was that the tables didn't exist yet, not the bootstrap phase? Can you clarify my understanding at all? I just don't want to use the phrase "requires a full bootstrap" unless that is really the problem. Maybe it should just say "This function should not be called from functions that may be...".
And I am also wondering if this information should be in a separate paragraph rather than being tacked onto the suggestion about using l() instead? It doesn't seem related to me.
Thoughts?
Comment #13
pillarsdotnet CreditAttribution: pillarsdotnet commentedMore accurate description moved to separate paragraph.
Comment #14
jhodgdonSince this new information is much less often needed (I think) than the l() suggestion, can we leave the l() information that was there first?
Also, table names should be in {} in documentation, because people can use table prefixes.
The other thing is... When I read this new paragraph, assuming I hadn't read this issue first, my reaction was that this was a giant logical leap: Huh? How is url_alias table connected to install profiles?!? I don't think we want to explain the whole chain of logic, but... And maybe it would be good to start with the "Don't use this in xyz" and then continue with an explanation that is not missing huge steps in logic? I don't know how to reword it, but the explanation there didn't really satisfy me.
Comment #15
pillarsdotnet CreditAttribution: pillarsdotnet commentedIs this better?
Comment #16
sven.lauer CreditAttribution: sven.lauer commentedThis issue is even more far-reaching: hook_install() implementations are free to invoke functions that have nothing to do with installation (the whole .module file is available to them). So maybe we should say:
Comment #17
pillarsdotnet CreditAttribution: pillarsdotnet commentedIs this better?
Comment #18
pillarsdotnet CreditAttribution: pillarsdotnet commentedMinor correction in grammar.
Comment #19
pillarsdotnet CreditAttribution: pillarsdotnet commentedAnd another.
Comment #20
jhodgdonI'm wondering about the wisdom of this change. There are a whole bunch of functions that probably shouldn't be called from these places, not just URL. Wouldn't it be better to document this on hook_enable(), hook_install(), and hook_requirements('install') -- and say something like "Don't call functions that access the database" there?
Comment #21
pillarsdotnet CreditAttribution: pillarsdotnet commented@#20 by jhodgdon on October 16, 2011 at 8:06pm:
Yes, this limitation should definitely be documented there, also.
Absent such a warning, a naïve user such as myself may incorrectly assume that
url()
andl()
would have no need to access the database in order to format an HTML hyperlink, or that a profile would install core/modules
beforesites/all/modules
.In fact, I would like to propose that in some future version of Drupal, all core functions must indicate the scope(s) for which their use is valid:
Global (no dependencies).
Partial bootstrap (specify the minimum level).
Installer profiles.
See also:
#241086: Install profiles cannot use drupal_get_path()
#555948: hook_requirements() is executed before dependencies are installed
#633332: hook API documentation files have no information about where hooks are to go
#794192: Documentation of hook_update_N() should explain that certain functions cannot be called from there
#833192: Installer might install modules in wrong order
#1006714: drupal_get_path doesn't work for profiles
#1247626: hook_install/hook_uninstall doc does not specify that the implementations must live in the .install file
Comment #22
pillarsdotnet CreditAttribution: pillarsdotnet commentedWarning reduced to a bare minimum.
Comment #23
apadernoActually,
url()
doesn't always access the path alias table. In fact, it contains the following code:If I set
$options['alias']
toTRUE
,drupal_get_path_alias()
will not be called.I think it makes more sense to add a warning about invoking functions that could cause a database access in installation profiles.
Comment #24
pillarsdotnet CreditAttribution: pillarsdotnet commentedUnfortunately, the installation profile author has no control over the contents of
$module.install
files. I doubt, therefore, that adding a warning to the installation profile documentation would be effective.Although specific people (such as yourself) may have more or less understanding of certain functions, I can't find a single reference anywhere that lists which functions may be called from which circumstances.
Certainly the Module developer's guide to writing
.install
files (both 6.x and 7.x versions) is no help.Comment #25
pillarsdotnet CreditAttribution: pillarsdotnet commentedMoved the warning to the alias option.
Comment #26
pillarsdotnet CreditAttribution: pillarsdotnet commentedComment #27
pillarsdotnet CreditAttribution: pillarsdotnet commentedBetter yet, simply set the default for 'alias' to
drupal_installation_attempted()
.Comment #27.0
pillarsdotnet CreditAttribution: pillarsdotnet commentedUpdated from issue summary template.
Comment #28
pillarsdotnet CreditAttribution: pillarsdotnet commentedYay, #27 passes tests!
Note that if this approach is selected, a corresponding test should be written to ensure that it stays fixed.
Comment #29
jhodgdonRemoving backport tag. This is not d7 material any more. I'm also unsubscribing. :)
Comment #29.0
jhodgdonVarious possible solutions listed.
Comment #29.1
pillarsdotnet CreditAttribution: pillarsdotnet commentedAdded limiting clause to introductory sentence.
Comment #30
pillarsdotnet CreditAttribution: pillarsdotnet commentedI don't see why at least one of the possible resolutions couldn't be backported to D7.
Comment #30.0
pillarsdotnet CreditAttribution: pillarsdotnet commentedAnd another limiting clause at the end of the first paragraph.
Comment #31
DamienMcKennaThere are a whole bunch of odd bugs that can show via installation profiles that never show when enabling modules normally, so I'd be in favor of expanding the documentation and this patch.
Comment #32
pillarsdotnet CreditAttribution: pillarsdotnet commentedAnother option suggested by chx in IRC: skip alias expansion during install mode, regardless of the
$options['alias']
setting.Comment #32.0
pillarsdotnet CreditAttribution: pillarsdotnet commentedtypo
Comment #33
pillarsdotnet CreditAttribution: pillarsdotnet commentedComment #33.0
pillarsdotnet CreditAttribution: pillarsdotnet commentedAnother possible resolution.
Comment #34
pillarsdotnet CreditAttribution: pillarsdotnet commentedClosing in favor of #1311774: Prevent path functions from using database tables that have not yet been created.
Comment #34.0
pillarsdotnet CreditAttribution: pillarsdotnet commentedAnother possible resolution.