Tuesday, January 15, 2008

Drupal: Multi-site installation

In drupal, it is possible to create multiple sites from ONE drupal instance. There are lots of information out on the web show how to do it, but many times are confusing. Following are some summary steps to create multiple sites in drupal:

There are two url form for multi site: subdomain (site1.domain.com, site2.domain.com) and suburl (domain.com/site1, domain.com/site2).

Example:
I want to create couple sites: www.gt.com; www.gt.com/site1; site2.gt.com. I can also create something like this: site1.gt.com/site2

1. Add virtual server to apache
NameVirtualHost *:80


ServerAdmin name@databasepublish.com
DocumentRoot "c:/wamp/www"
ServerName localhost

AllowOverride All
Allow from all





ServerAdmin name@databasepublish.com
DocumentRoot "c:/wamp/www/multisite"
ServerName gt.com //this is good enough to take care of gt.com/site1; gt.com/site2 ... (but make sure set the symbolic link otherwise you will get "page not found" error
ServerAlias *.multisite.com //this takes care of: site1.gt.com; site2.gt.com .....
ErrorLog logs/multisite_error_log
CustomLog logs/air-access_log common


AllowOverride All



( REMEMBER: all sites must point to the drupal base installation directory, also make sure to set symbolic link if using suburl format)

2. Modify window host file to point to the domain name, the location of the host file can be refer from http://leoman730.blogspot.com/2007/07/hostfile-location.html


3. Create new directories ("gt.com"; "site1.gt.com"; "gt.com.site2" under ) in path_to_drupal_installation/sites.

Tip: the directory name must match the site location by replacing '/' with '.'

Copy the settings.php file the default directory into these new directories.
Modify the settings.php accordingly for base_url, and db_url parameter.

Ex: in "gt.com.site2" directory, the base_url should be set to
$base_url = 'http://gt.com/site2';

Also need to modify the db_url to point to the correct database for each site


4. Create symbolic link for subsite (This is need is using suburl format)
I am using wamp as example, add alias by create a new alias file. The code should looks like this:

Alias /site1 "c:/wamp/www/multisite/" //multiple alias can be added here


Options Indexes FollowSymLinks MultiViews
AllowOverride all
Order allow,deny
Allow from all



4. Don't run the install script yet. Create new database for each site using any available tool such as phpadmin, or mysql admin

5. If the re-write moudle for appach has not been turned on yet, you need to turn that on: See this post for more info: http://drupal.org/node/15365. Turn this on will enable drupal Clean URL feature

6. Very Important. After all these modification, restart apache server and mysql server

7. Go to the new site and run the install.php

Tuesday, January 08, 2008

Drupal: Clean URL setting

It happened to me last time when I have a fresh drupal instance install on my local machine, when I tried to enable "Clean URL" in the admin setting, it bing me back to the homepage. After digging the web for a while, I found that the cause of this is the setting in the apache httpd.conf file. Refer to: http://drupal.org/node/15365 for detail. Basically what we need to do is to enable the rewrite module. After enabled the module, restart the server, and it would work perfectly.

Friday, January 04, 2008

Drupal way :: A good article on Cache mechanism

An very helpful article on druapl cache mechanism that post from Lullabot:

Original article: click here

A beginner's guide to caching data

Building complicated, dynamic content in Drupal is easy, but it can come at a price. A lot of the stuff that makes a Web 2.0 site so cool can spell 'performance nightmare' under heavy load, thrashing the database to perform complex queries and expensive calculations every time a user looks at a node or loads a particular page.

One solution is to turn on page caching on Drupal's performance options administration page. That speeds things up for anonymous users by caching the output of each page, greatly reducing the number of DB queries needed when they hit the site. That doesn't help with logged in users, however: because page level caching is an all-or-nothing affair, it only works for the standardized, always-the-same view that anonymous users see when they arrive.

Eventually there comes a time when you have to dig in to your code, identify the database access hot spots, and add caching yourself. Fortunately, Drupal's built-in caching APIs and some simple guidelines can make that task easy.

The basics

The first rule of optimization and caching is this: never do something time consuming twice if you can hold onto the results and re-use them. Let's look at a simple example of that principle in action:

function my_module_function($reset = FALSE) {
static
$my_data;
if (!isset(
$my_data) || $reset) {
// Do your expensive calculations here, and populate $my_data
// with the correct stuff..
}
return
$my_data;
}
?>

The important part to look at in this function is the static variable named $my_data. Static variables start out empty the first time a function is called, but they keep the data they're populated with even when the function is called again. That means that we can check if the variable is already populated, and if so return it immediately without doing any more work.

This pattern appears all over the place in Drupal -- including key functions like node_load(). Calling node_load() for a particular node ID requires database hits the first time, but the resulting information is kept in a static variable for the duration of the page load. That way, displaying a node once in a list, a second time in a block, and a third time in a list of related links (for example) doesn't require three full trips to the database.

Another important feature is the use of the $reset variable. Caching is good, but occasionally you want to be sure you're getting the absolute freshest data available. Using a 'reset' variable in your function, and always performing the 'expensive' version of the function if it's set to TRUE, lets you bypass caching when you really need to.

Drupal's cache functions

You might notice that the static variable technique only stores data for the duration of a single page load. For even better performance, it's often possible to cache data in a more permanent fashion...

function my_module_function($reset = FALSE) {
static
$my_data;
if (!isset(
$my_data) || $reset) {
if (!
$reset && ($cache = cache_get('my_module_data')) && !empty($cache->data)) {
$my_data = unserialize($cache->data);
}
else {
// Do your expensive calculations here, and populate $my_data
// with the correct stuff..
cache_set('my_module_data', 'cache', serialize($my_data));
}
}
return
$my_data;
}
?>

This version of the function still uses the static variable, but it adds another layer: database caching. Drupal's APIs provide three key functions you'll need to be familiar with: cache_get(), cache_set(), and cache_clear_all(). Let's look at how they're used.

After the initial check of the static variable, this function checks Drupal's cache for data stored with a particular key. If it finds it, and the $cache->data element isn't empty, it unserializes the stored data and sticks it into the $my_data variable.

If no cached version is found (or if we called the function using the $reset parameter), the function does the actual work of generating the data. Then it serializes it, and save it TO the cache so future requests will find it. The key that you pass in as the first parameter can by anything you choose, though it's important to avoid colliding with any other modules' keys. Starting the key with the name of your module is always a good idea.

The end result? A slick little function that saves time whenever it can -- first checking for an in-memory copy of the data, then checking the cache, and finally calculating it from scratch if necessary. You'll see this pattern a lot if you dig into the guts of data-intensive Drupal modules.

Keeping up to date

What happens, though, if the data that you've cached becomes outdated and needs to be recalculated? By default, cached information stays around until some module explicitly calls the cache_clear_all() function, emptying out your record. If your data is updated sporadically, you might consider simply calling cache_clear_all('my_module_data', 'cache') each time you save the changes to it. If you're caching quite a few pieces of data (perhaps versions of a particular block for each role on the site), there's a third 'wildcard' parameter:

('my_module', 'cache', TRUE);
?>

This clears out all the cache values whose keys start with 'my_module'.

If you don't need your cached data to be perfectly up-to-the-second, but you want to keep it reasonably fresh, you can also pass in an expiration date to the cache_set() function. For example:

('my_module_data', 'cache', serialize($my_data), time() + 360);
?>

The final parameter is a unix timestamp value representing the 'expiration date' of the cache data. The easiest way to calculate it is to use the time() function, and add the data's desired lifetime in seconds. Expired entries will be automatically discarded as they pass that date.

Advanced caching

You might have noticed that cache_set()'s second parameter is 'cache' -- the name of the table that stores the default cache data. If you're storing large amounts of data in the cache, you can set up your own dedicated cache table and pass its name into the function. That will help keep your cache lookups speedy no matter what other modules are sticking into their own tables. The Views module uses that technique to maintain full control over when its cache data is cleared.

If you're really hoping to squeeze the most out of your server, Drupal also supports the use of alternative caching systems. By changing a single line in your site's settings.php file, you can point it to different implementations of the standard cache_set(), cache_get(), and cache_clear_all() functions. File-based caching, integration with the open source memcached project, and other approaches are all possible. As long as you've used the standard Drupal caching functions, your module's code won't have to be altered.

A few caveats

Like all good things, it's possible to overdo it with caching. Sometimes, it just doesn't make sense -- if you're looking up a single record from a table, saving the result to a database cache is silly. Using the Devel module is a good way to spot the functions where caching will pay off: it can log the queries that are used on your site and highlight the ones that are slow, or the ones that are repeated numerous times on each page.

Other times, the data you're using will just be a bad fit for the standard caching system. If you need to join cached data in SQL queries, for example, cache_set()'s practice of string data as a serialized string will be a problem. In those cases, you'll need to come up with a solution that's specific to your module. VotingAPI maintains one table full of individual votes and another table full of calculated results (averages, sums, etc.) for quick joining when sorting and filtering nodes.

Finally, it's important to remember that the cache is not long term storage! Since other modules can call cache_clear_all() and wipe it out, you should never put something into it if you can't recalculate it again using the original source data.

Go west, young Drupaler!

Congratulations: you now have a powerful set of tools to speed up your code! Go forth, and optimize.

Thursday, January 03, 2008

Drupal menu cache

There's an very annoying issue in drupal menu. Suppose you are writing your own module and register it with some menu paths. What if later on you want to change some of the path setting in your module, for example, changing access privilege of a form. I discovered that even I save all my modification, my drupal site still not getting anything changed.
After some diggings, the main cause of these problem is the menu_cache table, where it cache the meun path for fast access. Root cause, modifying the module menu path does not automatically update the menu_cache table. Action, clean all cache in the menu_cache table, the change gets reflected.

Note: Caching cause a lot of confusion when developing in drupal, getting an understanding of how caching mechanism work in drupal is necessary. Also, sometimes is useful to clean cache of your browser when testing.

Wednesday, January 02, 2008

drupal_set_message

Recently I found this is a very useful function to gain information of a drupal page. It could print out the info on top of the page.

For example, to get all the name of text area field, I can put the follow little code on:

function mythemename_tinymce_theme($init, $textarea_name, $theme_name, $is_running) {
drupal_set_message($textarea_name);
}