2009-08-19

Drupal Pathauto: Bilingual stop word list

I've taken some time to update the stop-word lists for the pathauto module.

English (slightly modified module defaults):
a,an,and,as,at,but,by,for,from,is,in,into,like,of,on,onto,
or,now,per,than,the,this,that,to,up,via,with


German (requires transliteration module to properly convert diacritic marks (Umlaute)):
ab,aber,als,an,auf,bei,bis,der,die,das,dem,des,dies,durch,
ein,eine,einer,eines,fuer,ist,im,in,jetzt,mit,noch,oder,
per,sich,um,und,via,von,vom,zu,zum,zur


Hint: since pathauto is currently not language-agnostic, you need to copy both lists into the configuration field ("Strings to Remove").

2009-08-04

Drupal should be embeddable

Drupal 6 is currently not embeddable into third-party PHP applications, because bootstrapping alters the environment. Here's a fairly comprehensive list of modifications (in order of execution):
  • during DRUPAL_BOOTSTRAP_CONFIGURATION:
    • drupal_unset_globals() modifies global variables
    • conf_init() changes the session name
  • during DRUPAL_BOOTSTRAP_SESSION:
    • modifies the session handlers and starts a session
  • during DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE:
    • drupal_page_header() outputs headers
  • during DRUPAL_BOOTSTRAP_FULL:
    • _drupal_bootstrap_full() modifies the error handler, sets a new system locale, and strips slashes from request variables.
To resolve these issues, the integrating code should have the possibility to set a flag that tells Drupal to bootstrap without altering the existing environment.

Embedding Drupal means to include its front controller (index.php), bootstrap and execute a module function from within another PHP application.

2009-07-02

Drupal Admin Menu: Move out developer functions

Currently, Admin Menu has all those neat little helper functions like Clear cache and Disable developer modules built into the core module. To speed up future development, however, it would be great to have them separated into a dependent sub-module, which could then be developed at individual speed.

Along with my former idea of a site switcher module, this could also include more settings for existing functionality, like the Disable developer modules function, which could expose a list of modules and allow the admin to select which ones to disable, instead of just relying on a hard-coded built-in list.

The following existing functionality could be easily moved into its own submodule, in favor of a slimmer main module:
  • Switch user
  • Devel functions
  • Disable developer modules

2009-05-15

-moz-transform on table headers

While working on a new feature for DrupalvB, a Drupal module that integrates the vBulletin forum software into the Drupal CMS, I had to create a rather large matrix table allowing to map Drupal roles to vBulletin user groups. Because the group titles in the table header took up most of the space, I decided to test drive an upcoming CSS3 feature in Firefox 3.5: -moz-transform: rotate(). Here's what the result looked like:

-moz-transform on table headers
Note: the bad font rendering quality isn't the fault of Firefox, rather it comes from using an old version of M$ Terminal Server which doesn't support antialiasing.


Unfortunately, rotating elements just cuts the element out of its current position and draws it with the transformation applied, but doesn't touch the reserved space of the untransformed element. This lets the rotated text paint over adjacent DOM elements. However, since the length of the text is dynamic and thus not known in advance, trying to avoid this would need dynamic calculation of the required padding.

2009-05-11

Drupal Menu Trails: Support for node/add pages, please

The Menu Trails module currently only allows to set the ancestry of nodes when viewing them.

It would be extremely useful if the breadcrumb for node/add pages could be customized, too. That is, get rid of the so out-of-context Home >> Create content ancestry path. For example, one could put a certain content type in the context of the current user's profile (aren't contents somehow always related to a specific user, if we neglect anonymous users?), which would make the breadcrumb display Home >> My profile >> Create foo instead. Note: in this case, however, Menu Trails would need to provide a dummy item that represents the user profile of the current user — because it's a dynamic url.

Oh, and it would be totally awesome if this feature would be immediately available for project page's create new issue URLs to find an easy way back to the issue queue you were just in. ;)

2009-05-07

On Drupal performance: Delay loading objects

Drupal 6 performance currently seriously suffers from the fact that it always loads full objects (nodes, users, etc.) in advance. For example, invoking user_load() leads to a cascade of additional database queries, in this case at least one extra query to load the roles of the user. Whether the roles of the user are later actually accessed or not makes no difference, since Drupal doesn't care! For example, even if you're just going to display the user name and picture, Drupal loads completely irrelevant data.

I would therefore like to propose the following:

Replace anonymous objects with dedicated objects implementing a getter method

If the currently anonymous objects (nodes, users, etc.) returned from database queries could be replaced with "real" objects, uninitialized properties of these objects could be loaded on demand at the time of access by using the getter method of PHP 5 objects. To be able to do this, every such first-class object would have to ask all modules for a list of properties they implement beforehand. On access of an uninitialized property, the object would then delegate the loading to the responsible module.

Example:
  1. A user object is requested and initialized with just a user id (by invoking user_load()).
  2. An empty object is created, and initialized with the available properties (in this case no more than the user id, but could be more if available).
  3. An uninitialized property is accessed.
  4. The getter method of the object determines the module in charge.
  5. The module is ordered to load to property.
  6. The property is returned to the caller.

At this point it is important to understand that modules should not load single fields, but whole database rows. This saves us from additional queries on subsequent accesses to other properties handled by the same module (and we're basically getting them for free).
Also, SQL queries could be constructed as simple as possible (avoid complex JOINs), which gives us in certain cases better database performance (if you take MySQL's query cache, for example, simpler queries might have a longer lifetime in the cache because less tables are involved).

A concrete example would be a node query that currently also returns certain (but in some cases insufficient) user data (usually user id and author name): with dedicated objects it is not required anymore to JOIN the user table, because the user id contained in the node table is sufficient to initialize a user object. All properties that are accessed later will be loaded on demand, including often neglected items like the user picture, which are a requirement for modules such as User Display API, which allows to customize the display of user information.

Since all the loading is encapsulated and handled by the object itself instead of hard-coding it in the source module, we'd have transparent access to any defined property, at any time.

Adding support for methods ("mixins")

Since this concept has a certain similarity with the mixin pattern, one thing that almost instantaneously comes to mind: would it be useful to allow the same technique for methods? There are approaches that simulate mixins in PHP, albeit rather hackish (or, let's say leveraging what PHP has to offer). In the end, contrib modules would be allowed to not just extend object properties, but also specify additional methods.

2009-05-04

Drupal Admin Menu: Add a site switcher link

Simple idea for Drupal Administration Menu: When working on a local development copy of a site, sooner or later the changes made need to be ported to the production site. Now, instead of changing the domain name manually by fiddling with the mouse trying to select it, wouldn't it be way cooler to have a link somewhere in admin menu that allows you to open the current path on the production site counterpart (or locally, depending on where you currently are)?

The module should have exactly two configuration settings: the domain of the development site and one of the production site. All the module has to do is output the 'right' one (ie. the counterpart of the current host name).

Instead of outputting a link, the module should also provide new icons that show the developer where he/she currently is (for those to be easily confused, I could imagine this to be a nice visual feedback).

2009-05-02

Better diffing with Beyond Compare 2.x

Beyond Compare (still on 2.x tho) is a great program when it comes to diffing code changes. Unfortunately, the default settings e.g. for PHP don't handle differences in the number of function blocks very well (look at the screenshot, it should be self-explaining):


A simple addition to BC's alignment settings can be used to correct this behavior: Go to Options >> Rules >> PHP >> Alignment, and add a new regular expression for a line alignment:

Regular expression: ^\s+\}
Weight: 1

This will reduce the importance of curly brackets that are not at the very beginning of a line.

2009-04-30

hook_message_alter() for Drupal 7?

Since having spent a lot of time hacking around Drupal's inability to customize its status messages, I desperately hope that #234320: Add hook_message_alter() will be part of the next Drupal version.

Ok, the proposed patch is a little inconsistent: I would rather go for a watchdog()-like implementation, which at least requires an id, and receives both the untranslated message plus any arguments, to allow for maximum customization.

The result could look like this:
drupal_set_message('node_created', 'Your %post has been created.', array('%post' => node_get_types('name', $node)))

2009-04-29

Update GeoLite City via cron

Instead of manually downloading MaxMind's GeoLite City database, let cron do it for you. Here's how:
crontab -eu wwwrun
(or whatever your webserver user is)
# Update GeoLite City database on the 3rd of each month.
0 6 3 * * wget -qO /target/path/GeoLiteCity.dat.gz http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz && gunzip -qf /target/path/GeoLiteCity.dat.gz