Learning the Drupal Internals
Been studying and learning the Drupal internal codes so that I can contribute to Drupal eventually.
To be able to contribute sooner, I'm hoping that the Drupal experts who knows the internal very well can give me hints and pointers on how the internal works thus allowing me to understand and learn quicker.
I have been trying to follow the code starting with index.php and I see that first the bootstrap.php is loaded and the configuration file is included. After that, "drupal_page_header()" is called, and if caching is set, Drupal will serve the cached version of the page and set the HTTP header. (right so far?)
If cache are not enabled/available, then Drupal proceeds to set the header to current date and time and then include common.php which includes several files, set the Content type in the header, build its path and then loads all module with "hook_init" and then a "hook_exit" (right so far?)
The thing is, when I look into the module codes, I dont see the corresponding function for "hook_init" or "hook_exit"? Am I missing something here?
The modules I checked out for the init and exit hook calls are the following...
block
user
system
filter
node
page
story
watchdog
locale
and all of them dont have those init and exit hooks call.
Where in the codes does remaining hook calls are hooked into Drupal?
Where and when is the theme engine loaded to incorporated theme?
I feel like I am missing something here, I have been tracking down calls, trying to find out what each call does, how and why. I dont see specific calls being made for specific hooks except for "init" and "exit" and even those are not incorporated into the modules listed above.
I've been reading the API, reading through the forums, trying to find something that would cover the above questions, but dont see it, if you can tell me the links that covers the above, I would be happy to read it, and if not, then please give me pointers on how the Drupal internals work.
Thanks,
BlueDrupal

Some links
Page serving: http://www.lo.redjupiter.com/gems/iowa/drupalwalk.png
Page serving: http://drupal.org/node/10858
Node building: http://drupal.org/node/10902
Menu building: http://drupal.org/node/10901
statistics and throttle
It is not a requirement to use every hook. You just add the hooks that you want in the module.
statistics and throttle are the only core modules that use hook_exit.
The magic module_invoke_all()
The first thing you need to understand about hooks in Drupal is that they are not functions. This is something that took me a while to understand - it's really not documented and explained thoroughly enough, at least, not anywhere that I've seen.
For example, if you're looking for where the _search hook is defined in the code, you won't find a function anywhere called hook_search(), even though that function is listed on drupaldocs.org.
That's right, drupaldocs.org is misleading in this regard - maybe there should be a note saying: note: this function does not actually exist in the code, or something like that.
What you will find, however, is this line of code in search.module:
<?phpmodule_invoke_all('search', 'reset');
?>
This code calls the magic module_invoke_all() function, which in turn makes use of PHP's
call_user_func_array()function to execute a dynamic function call (i.e. calling a function without knowing its name until run-time). Until I saw this function used in the Drupal code, and then investigated it, I didn't even realise that PHP could do this. But it's pretty cool, isn't it? And without it, Drupal wouldn't be the system we know and love.So when you're looking for where a hook's defined, don't look for functions called
hook_foobar(). Look for lines of code that say:<?phpmodule_invoke_all('foobar', 'abc');
?>
Jeremy Epstein - GreenAsh
great explanation
now that you mention it, i bet this trips up a lot of newbies. this is so core to drupal that we fail to explain it well. please improve the docs to include this point. consider writing a book entry or editing the Contrib/docs files.
thanks.
A great starting place...
...is Drupaldocs.org, which is the API documentation (documentation for module developers).
Basically the hook_ functions are API functions that are "overloaded" as needed by modules. The system invokes the hooks as it comes to a spot where a hook is to be run, and the modules respond as they see fit. A module doesn't have to respond to all hooks (only the ones it cares about).
Theming is similar, as modules make "theme requests" (as opposed to hook invokes) and the themes respond to them as best they can.
--WorldMaker--
I understand how hooks work...
I understand how hooks works, but the thing is , when u look at the call made by common.inc, "module_init" it makes a call to module.inc, which in turn calls a function "module_invoke_all('init')".
As you can see, the function invoke all modules with the hook "init". Now looking into the required modules needed by Drupal, i dont see any of those hook call implemented into those required module.
For example, I look into the block.module, and the block module doesnt implement this function "block_init" which is fine and dandy since modules dont have to implement every single functions.
But the problem is all of the required modules doesnt implement either hook "init" or "exit" which makes me wonder how do they get hooked into Drupal. I followed the code starting with index.php trying to track down exactly what Drupal is doing when a user first a Drupal-powered site.
And on top of that, when tracing down codes, I dont see theme engine being implemented, it only includes theme.module, but no calls are being made to theme.module nor is theme.module executing any code once it is included. And as pointed out in one of the link, http://drupal.org/node/10858, this document states that in common.inc, it makes a call to "init_theme()"
In Drupal 4.6 (the one i am using) does not have this call in common.inc nor is it making that call anywhere when tracing down the codes starting with index.php.
How is theme engine able to create theme and send it to user if no calls are being made to theme.inc?
BlueDrupal
At least tell me where theme engine is loaded
At least please point me to where theme engine is loaded.
IN the document, it states that "init_theme()" is called in common.inc. But if you will look into common.inc for Drupal 4.6. there are no such call.
Where is this call being made? theme.inc have this function, but whos calling it? from where?
it is not in bootstrap.inc or common.inc so where else can this call be made from what originating function in either bootstrap.inc or common.inc?
drupaldocs
drupaldocs has the answers
If that doesn't make sense, it means init_theme() is called by theme(), in theme.inc. This ensures that the theme engine and theme are only loaded if/when the user tries to output a themed element.
it means init_theme() is called by theme()...
Great...
Now, how is theme() called? from where? I do not see theme() call in either bootstrap.php or common.php.
Do you see my point? How the heck is theme() called? which will in turn call init_theme()?
I have been looking through drupaldocs for the past few days. Drupal docs does not show references made by either bootstrap.inc or common.inc when they first start up. References there are made in other function that doesnt get called when a visitor first visit 4.6 Drupal-powered website.
When you trace or track down codes starting from the beginning in index.php, you will see that theme() function are not called.
it simply does in the following order...
1. drupal_page_header()
2. some executable codes in common.inc when it gets included
3. fix_gpc_magic()
4. drupal_page_footer()
All of which does not call theme() function, if you were to try to trace down the call.
I also know about directory scanning capabilty that scans directory for modules and theme. Those function also dont get called when tracing down codes starting with index.php
I know this may sounds persistent, but I am trying and I want to be able to understand how this works.
If someone can please point out the line number in the codes that begins with a call from either bootstrap.inc or common.inc and ends up at theme() function. Then I can figure the rest from there, but right now I see no relation between the files, and how they are getting called.
Much appreciation,
BlueDrupal
http://drupaldocs.org/api/4.6/function/theme/references
According to the drupaldocs page above, I understand that theme() is called at page creation by modules that output themed content.
--
Bjorn | choirgeek.com
Is drupaldocs not enough?
DrupalDocs gives you the information you've asked for by letting you see which functions are where, what code they contain, what calls them - almost everything about them.
The last part is a little more complicated. I don't know much about the menu internals, but here's a brief breakdown:
watchdog_overview()), which generates a load of output and either returns it to index.php (in CVS), or runs it through the theme() function directly.I'm happy to give more detail if required, but a line by line walk-through isn't likely to reveal much unless you did that by yourself.
Suprisingly no...
While DrupalDocs do provide api calls, the docs does not explain exactly how the internals works.
By internals, I mean how does the Drupal "engine" works? How is it calling functions implemented in modules?
At first, I had trouble finding out what function is calling all the other functions implemented in module, but realized that it is implemented as callback in menu array. The callback is realized by the path that is passed to the "engine", the 'q' variable.
I have a great interest in CMS and have been playing around with several CMSes (if that is a word). By far Drupal has the cleanest code structure IMO and the ability to implement hooks is a fantastic tools to have. The idea of using menu arrays as a engine to make Drupal runs is a great flexible implementation to use. This allows for easy growth and expansion in the future.
The only other CMS that I think can be compared to Drupal is PHPWebsite. While they are implmented differently than Drupal, their code is clean and is easy to follow. One can jump in and begin creating modules for them. The only downside is not a big community following and not alot of modules available to have a fully functioning "out of the box" live website.
The only thing I didnt like about Drupal is the blocks, it can only be used on the right or left side of the page. But I think, without much understanding of the theme engine, Drupal has enough flexibility that this can be implemented easily into the theme engine (i think?).
Any more details you can give will be greatly appreciated such as details about the menu array, maybe something that is not immediately known when doing line by line. Anything is appreciated, other than that, i am doing line by line walk through all the codes available just to have a good understanding of it is doing and maybe how it can be improved.
Other than that, all those involved in any aspect of Drupal, YOU HAVE DONE A GREAT JOB!
Keep up the good work!
BlueDrupal
Blocks
"Right" and "Left" Blocks are just the most common way for a theme to handle them. They really are only a hint given to the theme engine. A Theme is free to put them anywhere, but the "easiest" (in terms of layout) is often left and right hand columns.
I did see a theme where the Left/Right blocks were instead Top/Bottom elements. I also saw a theme where the blocks were in DHTML "menus" that dropped down from a bar. Neither seem to be on the themes page, though.
With any good minimalistic XHTML theme you could probably do either in CSS alone without having to know a thing about theme code.
--WorldMaker--
system table
I don't know if you've seen this yet but all the physical files involved (modules, themes) get read by directory scans and saved in the system table. This is perhaps a missing piece in the puzzle when it comes to loading the modules and calling the hooks.
- Robert Douglass
-----
If this helped you, please take the time to rate the value of this post: http://rate.affero.net/robertDouglass/
www.hornroller.com, www.robshouse.net
New Comments above at ...
http://drupal.org/node/26040#comment-45436
Step by Step
If you will step through Drupal 4.6 codes with me, lets start with theme.inc that is being included in common.inc on around line #1964
From there, as theme.inc is being included, no executable codes is being executed.
-----------------
Then the next six (6) files is being included
include_once 'includes/pager.inc';
include_once 'includes/menu.inc';
include_once 'includes/tablesort.inc';
include_once 'includes/file.inc';
include_once 'includes/xmlrpc.inc';
include_once 'includes/image.inc';
none of which when included run any executable code.
-----------------
then a call to "drupal_set_header('Content-Type: text/html; charset=utf-8');" is made, which simply deals with header for current page.
-----------------
After the header is set, common.inc runs the next few lines of code as following...
if (!empty($_GET['q'])) {
$_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
}
else {
$_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
}
Which, from my understanding simply deals with variable being passed. if no variable is passed then it assume that user is requesting the home page.
-----------------
Once the variables in the path has been parsed, Drupal now loads module with the next line of code
module_init();
which is a function inside module.inc file. Inside that function two fuctions are called...
module_load_all();
module_invoke_all('init');
Both functions, once again is inside module.inc file. The first function module_load_all() deals with loading all module that is of type 'module' and then the next function, invoke the hook call that is implemented by any of the module that is loaded by using this 'hook_init' with hook being the module name. The module may or may not implement the init function.
By looking into only the required module needed by Drupal, I see that none of those required module implemented the 'init' hook function. Which tells me nothing is being done with those module when they first load.
-----------------
After the module loads, the following is executed...
if (!user_access('bypass input data check')) {
// We can't use $_REQUEST because it consists of the contents of $_POST,
// $_GET and $_COOKIE: if any of the input arrays share a key, only one
// value will be verified.
if (!valid_input_data($_GET)
|| !valid_input_data($_POST)
|| !valid_input_data($_COOKIE)
|| !valid_input_data($_FILES)) {
die('Terminated request because of suspicious input data.');
}
}
Those simply check the data passed for any illegal characters.
-----------------
Once the data validates, the following is called...
// Initialize the localization system.
$locale = locale_initialize();
The function is in common.inc and is simply used to set the preferred language, and default to english.
-----------------
Now, all the codes has been executed in common.inc and the control returns to index.php
Index.php then runs this function...
fix_gpc_magic() which simply just check Get, Post, Cookie variables. The function resides in common.inc
-----------------
Then a call is made to
$status =menu_execute_active_handler();
which lives in menu.inc file. Then depending on the condition of the variable $status, Drupal may shut down if $status is set to either MENU_NOT_FOUND or MENU_ACCESS_DENIED.
If either one of these condition is true, then the following functions is called...
drupal_not_found();
or
drupal_access_denied();
Now if you will look inside those functions, they make a call to "theme()" but that is only if $status variable is set to one of the either constant variable.
But lets assume that all is well with Drupal and $status variable does not point to either one of those constant variable.
-----------------
The last method in index.php is
drupal_page_footer();
and that function resides in common.inc. The function simply execute the next few lines of code as the following...
if (variable_get('cache', 0)) {
page_set_cache();
}
module_invoke_all('exit');
the first line states that if caching is enabled, then cache the page. On my drupal website, i turned off caching for the sake of simplicity, and to understand what is happening with the codes.
So...caching function is not called, and it moves on to the next line of code which is a function...
module_invoke_all('exit');
this function use the function "hook_exit" with hook being the module name to give modules last chance to do any additional logics. Once again, if you will look into all required modules needed by Drupal, you will see that none of these require modules implement this hook call.
-----------------
Drupal now close up the shop and serve the page.
Now if you will see, no where in the code when I trace it makes a call to "theme()" function with an exception for the two function that runs when error occurs.
Assuming that Drupal is able to execute code without any type or sort of error, it should have made a call to function "theme()"
-----------------
I hope this clarify things up. And hope someone can take the time to show me what I am missing.
I realize that I am too persistent and may look like the biggest fool on the block. But that is okay with me, as long I can understand it. I would rather look like a fool and understand how things work rather than being ignorant and stay a fool.
Thanks,
BlueDrupal
debug_backtrace();
In situations like this it can be really helpful to go to the code you're interested in and add the line:
print_r(debug_backtrace(), true);
That will show you how you got to where you are and you won't have to wonder "where did this function get called?"
- Robert Douglass
-----
If this helped you, please take the time to rate the value of this post: http://rate.affero.net/robertDouglass/
www.hornroller.com, www.robshouse.net
debug_backtrace() is a big help....
wish I had knew about it, it would have saved me time on studying the codes.
Thanks robertDouglass.
on a side note, it would be nice to be able to choose the post that was the most helpful. It may save time for the future Drupal users when they are trying to find a quick answer and dont want to read all the posting, just go straight to the post that was the most helpful. Something similar to what Experts-Exchange.com is doing.
book page
BlueDrupal, how about you write a summary of what helped you the most and create a handbook page. Maybe in the Contributor FAQ section. This way it will live in the handbook instead of a random spot in the forum. :)
-sp
---------
Test site...always start with a test site.
Drupal Best Practices Guide
What you are missing....
Here's what you seem to missing, on the line:
$status = menu_execute_active_handler();
The key word here is "execute", because it doesn't just return a status, it also performs the "main" action of a page (based on the "menu" path). The comment for menu_execute_active_handler():
/**
* Execute the handler associated with the active menu item.
*
* This is called early in the page request. The active menu item is at
* this point determined exclusively by the URL. The handler that is called
* here may, as a side effect, change the active menu item so that later
* menu functions (that display the menus and breadcrumbs, for example)
* act as if the user were in a different location on the site.
*/
...and the key function is:
call_user_func_array($menu['items'][$mid]['callback'], $arguments);
This may be somewhat obscure, but what it does is it calls the "callback" function registered by some module to handle some URL path. On a node page, for instance, this will be in node.module.
You might want to look as the hook_menu() functions of the modules you are interested in.
--WorldMaker--