To explore the tech world, though mostly focusing on iOS, Django, and Drupal development Sometimes it isn’t the perfect that gets in the way of the good, but the revolutionary gets in the way of the evolutionary.

Book Review - Drupal Multimedia

Finally I have found time to read Drupal Multimedia. As an active multimedia developer Aaron Winborn has this topic covered.

Who is it for? You need to read this book if you are want to learn how to make Drupal pop with rich media. Helpful examples and walkthroughs for most of the well used modules are given. If you want to know more about any of these modules, or if you don't even know what these modules can do.

Quick Progression

  • Intro - CCK - Views - Themes
  • Images for admins and editors - Creating Gallery - Teasers - Embedded Images
  • Developing for Images
       Image node - Multiple images - Resizing - Views and slideshows
       Embedded Media
  • Theming Images - Styling Views - Investigating media theming - Overiding image nodes - Image affects

The middle chapters

Lastly Aaron ends the book with a 'Future of Drupal' section which covers what might be next for Drupal in:

  • File Handling
  • Multipurpose
  • UX
  • embedded widgets
  • Mobile web
  • New media - Second life/Wii

I have a few more extensive example that I want to share of how I implemented ideas from this book. But that is for another time. As I said that the start, if you are starting a new Drupal project and you want or need to add rich types of media, pick up this book to assist and enhance your projects.

Drupal, Start Here! - ebook

Whether you’re just starting your first website or you want to do a major web-based project, Drupal is a the way to bring your ideas to life and Drupal, Start Here will help you start quickly.

Drupal, Start Here is a fun, engaging tutorial that introduces Drupal and shows you how to build Drupal-powered sites quickly and easily. This friendly, fully-illustrated book starts with the absolute basics for the new Drupal user—setting up your computer to use Drupal, building your first pages, creating user accounts, and so forth. By following a series of interesting examples, you’ll learn to manage both small and large blocks of content and how to add navigational features like tags, menus, catalogs, and search.

Drupal, Start Here is for readers with little or no experience with Drupal. If you’ve done websites using another technology, this book will help you use what you already know in Drupal. If you’re brand new to the web, Drupal, Start Here is a great place to start your adventure.

Dispelling Node Access Fears

Venturing into the node access realm of hooks and functionality for some reason always felt complex, so I have avoided it complete thus far, relying on various node or taxonomy access based modules (http://drupal.org/taxonomy/term/74), to handle any access issues I needed. This usually resulted in systems that were more complex or more burdensome to maintain than desired. Well, I was wrong, the node access system isn't complex, and it is powerfully efficient and optimized.

Recently, I needed to implement a system to allow editing access to a node (an organization node) by multiple users, but we wanted the original node author to dole out this access instead of sending requests to the administrators. But beyond that we needed them to be able to edit all the 'product' nodes that referenced the 'organization' node.

A couple modules were close to what I needed (http://drupal.org/project/nodeaccess_autoreference, http://drupal.org/project/nodeaccess_userreference, http://drupal.org/project/nodeaccess_nodereference) but they were a bit more featured loaded than I wanted, and I used this as an opportunity to learn about the node access hooks (check out the node access example for a general example.).

To tackle my issue, I started with a user reference CCK item on the organization node, so the node author can assign other members to the node, and also added a node reference item to the product nodes to reference an organization node.

Now that the links were in place, I had to implement the node access permissions. Even time a node is checked for 'edit' permissions the node grants hook is run, so my module needed to implement this hook.

function example_node_grants($account, $op) {
   //Keyed array with realm as key
   $grants['referenced'] = array($account->uid);
   return $grants;
}

From the API guide, I just needed to create an array with the key as the realm of access permissions (should not conflict with any other node access module you have, if any). I called the realm 'referenced' since I was using node and user references, and since it was user based, I just use the user ID as the item to look for.

In simple terms, this tells the node access system to look for an entry that links the user ID, with the requested node ID in the 'referenced' realm of entries.

But the check is useless unless we have already added grants to the system, so the node access record hook is needed.

Checking the API guide, I just needed to pass an array of arrays with the grants that needed to be saved.

function example_node_access_records($node) {
   if ($node->type == 'org') {
   //For each user referenced in the CCK item, add a grant entry.
   foreach($node->field_members as $u) {
     if (!empty($u['uid'])) {
       $r_user = user_load($u['uid']);
       $grants[] = array(
         'realm' => 'referenced',
         'gid' => $u['uid'],
         'grant_view' => TRUE,
         'grant_update' => TRUE,
         'grant_delete' => user_access('administer org', $r_user) ? 1 : 0,
         );
       }
     }
   }
   elseif ($node->type = 'product') {
     //For each 'org' node referenced, check for all user references to add grants.
     foreach($node->field_org_ref as $o) {
       if (!empty($o['nid'])) {
         $o_node = node_load($o['nid']);
       //For each user referenced in the CCK item, add a grant entry.
       foreach($o_node->field_members as $u) {
       if (!empty($u['uid'])) {
         $r_user = user_load($u['uid']);
         $grants[] = array(
         'realm' => 'referenced',
         'gid' => $u['uid'],
         'grant_view' => TRUE,
         'grant_update' => TRUE,
         'grant_delete' => user_access('administer org', $r_user) ? 1 : 0,
         );
         }
       }
       }
     }
   }

   return $grants;
}

When a node is saved, all the grants for that node are re-calculated. But I had an issue where I needed to also resave all the referenced 'product' nodes with new permissions each time the 'org' node was updated. So I needed to also make a nodeapi hook entry to save new grants for any referenced 'product' nodes.

function example_nodeapi(&$node, $op) {
if ($op == 'update' or $op == 'insert') {
//Update node access table with grants of the author and members of an org
if ($node->type == 'org') {
//Add grants for all products that reference this node.

$qry = db_query("SELECT DISTINCT(nid) FROM content_type_product WHERE field_org_ref_nid = %d",$node->nid);
while ($result = db_fetch_object($qry)) {
$grants = array();
foreach($node->field_members as $u) {
if (!empty($u['uid'])) {
$r_user = user_load($u['uid']);
$grants[] = array(
'realm' => 'referenced',
'gid' => $u['uid'],
'grant_view' => TRUE,
'grant_update' => TRUE,
'grant_delete' => user_access('administer org', $r_user) ? 1 : 0,
);
}
}
node_access_write_grants($result, $grants, 'referenced');
}
}
}
}

The node_access_write_grants function takes the same array entries like the node access records hook. It isn't needed to be called oin the node access records hook because the grants are written later through the hook loop, but in the nodeapi() implementation, we have to explicitly call the write grants function to make sure they are saved.

To round out the permissions carefully, I turned on the CCK permissions modules and protected both the user reference and node reference fields so that members with this new delegated power can't add or remove other people from the editing powers. Only the node author can do that.

Now that I have done it once, I won't be nearly as fearful regarding the node access system, and I have found how optimized this system is. Great job Drupal core developers.

YSlow Small site review

I always check YSlow before a new site launch, but I don't remember when they updated the look and functionality. Maybe it is the FF 3.5 version. But regardless it is great to see that the look resembles the vertical tabs from the new content editing form in Drupal 7.


Click for large image.

Beyond the surface change, the have also added a new Small Site or Blog setting that changes what is evaluated, CDN, Etags, Cookie Domains and AJAX compression are not used in the scoring.

This is encouraging since the new site now has a score of 89. Then when I turn on CCS and JS aggregation the score jumps to 98. I imagine reducing background images and moving a few more JS scripts to the bottom would get close to a perfect 100, but I am not reaching for that number anyway.

But the new scoring is great since it focuses on what small to mid-level sites can actually work on, since CDN and JS/AJAX compression is just not really workable for such sites. A score of 98 lets me know that I am really done with the stuff that should concern a smaller sized site.

Embedded Video How To - Start Youtube mid-video

Here is a simple trick that I learned while creating a small, fun video site on a whim. The main problem is that we wanted to start some Youtube videos at a specific interval in the video, say 30 seconds in. We were already use the Embedded Media Field set of modules of CCK (http://drupal.org/project/emfield, with the video/youtube addon modules), but mid-video starts aren't supported (yet as I will submit a patch shortly to add this functionality to the options array).

I will write more about the full site build at a later time, but here is what I did to tackle this issue. I am assuming that you are familiar with CCK, EM Field modules and a bit of knowledge to theme a node template.

Here is what I did:

1) Create the embedded video field for youtube ('field_song_video' in my implementation).
2) Create am integer field to hold the number of seconds into the video to start ('field_song_start' in my implementation).
3) Remove from Display on the node both of these fields.
4) Updated my node-songs.tpl.php (replace with your appropriate node template file).
5) Where I wanted my video to be embedded I placed the following code:

<?php print theme('emvideo_youtube_flash', $node->field_song_video[0]['value'] .'&start='.$node->field_song_start[0]['value'], 450, 350, 0); ?>

The main part to notice is the '&start=...' part. The theming function for the youtube player will add the start variable to the Youtube request URL which will start the video at a later place than the beginning. The other arguments are the size of the player (450px by 350px) and the auto-start flag.

NOTE: The API has changed a bit since my site implementation so the new code would look like this (replace 'emvideo_youtube_flash' with 'video_cck_youtube_flash').

<?php print theme('video_cck_youtube_flash', $node->field_song_video[0]['value'] .'&start='.$node->field_song_start[0]['value'], 450, 350, 0); ?>

Version Controlling your sites folder, Subversion

While at the DC DrupalCon, I was in a lecture of how to boost you Drupal efficiency through various means and tools. One of course is to have all your code in a some version control system. Drupal.org uses CVS, while many people use Git or Subversion, and there are others besides.

When using a multi-site setup, there is a need to be a bit more careful so that an update to one site doesn't affect other sites. Of course you should be using the sites folders for all the different sites in your multi-site setup (such setup is beyond the scope of this article).

One way for me to keep track of all my code is to have the main code (Drupal core and the sites/all folder) in one repository. Then place each specific sites folder (sites/example1.com, sites/example2.com.....) each in their own repository. This way you cleanly separate your code out, and prevents UPDATES from hitting more code than you want it to.

Doing this in SVN can be a little tricky, since I have gotten into crazy LOCKs and Conflicts. Here is how I did it.

  1. Checkout/Create your main repository and add the normal Drupal core, along with the sites/all folder (add in all the common modules and themes as normal.
  2. Commit this to the repository.
  3. Create empty sites folder as needed, leave empty (sites/exmaple1.com ...).
  4. Use the Ignore command on each of these folder.
  5. Commit these updates to the main repository (now all new files added to these folders will be ignored by the main repository.
  6. Checkout/Create new repositories for each of the sites folders, add your files/modules/themes.
  7. Commit each sites folder to its repository.

That is how to cleanly establish sub-repositories inside of a larger one, each exist independently of the others. Now code and commit at your leisure while as you follow the rule of always version controlling your code.

Turning off aliasing in l()

It is always a good things when a site grows large enough to worry about performance issues. With more users and longer reports, one site I regularly work on was having an issue building a reservation report page. Quickly I turned on Devel with its query log, checked the main query that builds the report, put it through EXPLAIN and optimized a few keys. But no real improvement was made.

So I looked again at the query log, and noticed that drupal_lookup_path() was being called 1000 times (as many results in the report, and yes the Project manager wants them all on one page). So I am making 1000+ individual queries to the url_alias table, each taking only a few ms, but added together it is slowing down the report.

This is what the offending line looks like:

... = l($reservation_id, 'reservation/info/'. $reservation_id);

I finally realized that I don't need aliasing on those links. They simply link to the information page of a particular reservation (reservation/info/34038) which will never, and should never be aliased.

Now my code looks like:

... = l($reservation_id, 'reservation/info/'. $reservation_id, array('alias' => TRUE));

A months worth of data now renders in seconds, instead of over a minute.

DrupalCon SFproposal support

It is surely time to bring the North American DrupalCon back to the West Coast. Visit the DrupalCon San Francisco proposal page and express your support.

And grab a badge while you are there.

Hosted Memcache??

Gear6 is creating a hosted memcache layer, http://www.gear6.com/web-cache/overview/scale-your-web-site-applications..., that may help bring memcache to sites that don't want to set up their own memcache servers. They are hoping that be a capacity player for large companies that already have memcache server farms, as well as opening up this technology to new, mid-tier websites. I am hoping this and other like services will quickly be assimilated into the network of Drupal integration modules for performance.

And by the way, the corporate and Gear6 Community sites were built with Drupal.

Flying out east for DC Drupalcan

Though Washington DC isn't as far as Boston from the SF Bay Area, the travel time will be longer with a stop over. But the North American DrupalCon is always worth the travel. Head over to the schedule to work out your days there.

While I am there one goal is to seek out people who are considering Drupal/iPhone app integrations. http://www.zivtech.com/blog/simplest-drupal-iphone-app is a start and I hope to see more progress one this front.

Syndicate content