Monday 26 September 2011

Automatic file download

I have a personal project I'm working on which requires an automatic download link. You know the sort of thing - like you get on SourceForge: "Your file will download in x seconds". And then the file download dialog pops up.

All the solutions for this are JavaScript - and if you want a countdown then JS is the way to go. But I didn't want JavaScript.

The basic part of the trick isn't limited to Drupal at all, you just HTML:

<meta http-equiv="Refresh" content="1; URL=http://www.yoursite.com/system/files/downloadfile.ext" />

So here, after one second, the page refreshes - except it's a file to be downloaded, so your browser does the right thing and gives you a download dialog box instead.

Easy.



Sunday 11 September 2011

field_extract module in beta

EDIT: Now out of beta. Fully implemented.

EDIT: You can now get the module from http://drupal.org/project/field_extract and it works properly with Drush.

My incredibly useful field_extract module is now available on drupal.org. I am slightly embarrassed because something went wrong in the project creation process so the actual URL is:

http://drupal.org/project/1158878

And when you download it the module comes inside another folder "1158878". In fact this will work just as it comes, you'll just get the folder 1158878 in your modules folder with field_extract inside that.

If you're competent you can extract the inner "field_extract" module and get rid of the outer 1158878 folder but, as I say, it should work out of the box anyway. (I may get around to re-uploading it properly at some point but I can't wait any longer to get it out to you.)

So what does it do? For a start, this is only a developer's module. It does nothing by itself and should only be downloaded if requested by another module. But what it does do is provide a couple of functions that make it much easier to extract field data from entities.

The project page provides clear instructions on how to use it.

Enjoy.

Wednesday 7 September 2011

Reducing the footprint

Sorry I haven't blogged in a while, I have been working very hard on commercial D7 sites in my day job but haven't really come across anything spectacularly D7 I wanted to talk about.

So here's something unspectacular but quite important, and applies almost as much to D6 as D7.

Every module eats memory. Every x.module file (for enabled modules) gets loaded for every access (well, let's ignore caching). So anything that can be done to reduce the files loaded (size in this case) can only be a good thing. (Back in the day I wrote code for machines with 128K of memory of which 20K might be used for the screen, and another 32K for the OS - in those days you really had to think about keeping code as compact as possible.)

Drupal uses hooks to gather information from modules, and then it stores this information in the database caches (or other tables), after which it no longer calls these hooks - unless the caches get cleared and it has to build the information again.

Hooks like hook_menu, hook_theme, hook_permission and so on. But these hooks need to be available in the x.module file - and yet they are only called infrequently.

Solution? Put a minimal hook in the x.module file which loads another file (say x.registry.inc) and then calls the actual hook code which is in there. Like this:

In x.module:

function x_menu() {
  module_load_include('registry.inc', 'x');
  return _x_menu();
}

And in x.registry.inc:

function _x_menu() {
  $items = array();


  $items['my/path'] = array(
    // my/path data  );


  return $items;
}

If a hook is called on pretty much every page there is no advantage in doing this. But if it's a hook that's called infrequently it's definitely worth it.

This is something I'd played with back in my D6 days but then stopped using. But then I saw another contributed module that was using it and thought "yep, I should be doing that". So I am and here it is.

hook_hook_info()

There is another solution using hook_hook_info() which allows you to define a file in which hooks can be found. This does not work for the majority of system modules because they use customised hook-calling methods. Only one system module - Tokens - has it defined so token code can be located in x.tokens.inc.

However the Block module only uses standard hook-calling functions and you could specify a file for block management using hook_hook_info_alter(); I wrote something about this here.