Index: views.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/views.module,v
retrieving revision 1.332.2.30
diff -u -p -r1.332.2.30 views.module
--- views.module	13 Aug 2010 23:13:16 -0000	1.332.2.30
+++ views.module	5 Oct 2010 17:46:20 -0000
@@ -429,6 +429,20 @@ function views_flush_caches() {
  */
 function views_invalidate_cache() {
   cache_clear_all('*', 'cache_views', true);
+  // Purge decorators' file cache.
+  _views_purge_decorator_cache();
+}
+
+/**
+ * Delete all the cached decorated handlers' files.
+ */
+function _views_purge_decorator_cache() {
+  $dir = file_scan_directory(file_directory_path() . '/views', '\.inc$');
+  if (is_array($dir)) {
+    foreach ($dir as $file) {
+      file_delete($file->filename);
+    }
+  }
 }
 
 /**
Index: includes/handlers.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/handlers.inc,v
retrieving revision 1.109.2.17
diff -u -p -r1.109.2.17 handlers.inc
--- includes/handlers.inc	30 Jun 2010 19:19:02 -0000	1.109.2.17
+++ includes/handlers.inc	5 Oct 2010 18:10:51 -0000
@@ -145,6 +145,7 @@ function views_fetch_handler_data($handl
  */
 function views_discover_handlers() {
   $cache = array();
+  $decorators = array();
   // Get handlers from all modules.
   foreach (module_implements('views_handlers') as $module) {
     $function = $module . '_views_handlers';
@@ -156,27 +157,136 @@ function views_discover_handlers() {
     $module_dir = isset($result['info']['module']) ? $result['info']['module'] : $module;
     $path = isset($result['info']['path']) ? $result['info']['path'] : drupal_get_path('module', $module_dir);
 
-    foreach ($result['handlers'] as $handler => $def) {
-      if (!isset($def['module'])) {
-        $def['module'] = $module_dir;
-      }
-      if (!isset($def['path'])) {
-        $def['path'] = $path;
+    if (isset($result['handlers'])) {
+      foreach ($result['handlers'] as $handler => $def) {
+        if (!isset($def['module'])) {
+          $def['module'] = $module_dir;
+        }
+        if (!isset($def['path'])) {
+          $def['path'] = $path;
+        }
+        if (!isset($def['file'])) {
+          $def['file'] = "$handler.inc";
+        }
+        if (!isset($def['handler'])) {
+          $def['handler'] = $handler;
+        }
+        // merge the new data in
+        $cache[$handler] = $def;
       }
-      if (!isset($def['file'])) {
-        $def['file'] = "$handler.inc";
+    }
+
+    if (isset($result['decorators'])) {
+      foreach ($result['decorators'] as $decorator => $def) {
+        if (!isset($def['module'])) {
+          $def['module'] = $module_dir;
+        }
+        if (!isset($def['path'])) {
+          $def['path'] = $path;
+        }
+        if (!isset($def['file'])) {
+          $def['file'] = "$decorator.inc";
+        }
+        if (!isset($def['handler'])) {
+          $def['handler'] = $decorator;
+        }
+        // Only save the decorators, do nothing, wait first for all the handlers to be cached.
+        $decorators[$decorator] = $def;
       }
-      if (!isset($def['handler'])) {
-        $def['handler'] = $handler;
+    }
+  }
+
+  // Loading decorated handlers definitions.
+  foreach ($decorators as $decorator => $decorator_def) {
+    // Decorate all the handlers which inherit from the decorator's parent and add them to the cache.
+    foreach ($cache as $handler => $handler_def) {
+      if (_views_handler_is_ancestor_of($decorator_def['parent'], $handler_def['parent'], $cache)) {
+        // Create a decorated handler.
+        $decorated_def = $decorator_def;
+        $decorated_handler = views_handler_decorated_name($handler, $decorator_def['module']);
+        $decorated_def['handler'] = $decorated_handler;
+        $decorated_def['parent'] = $handler;
+        $decorated_def['path'] = file_directory_path() . '/views';
+        $decorated_def['file'] = "$decorated_handler.inc";
+
+        // Cache its file.
+        _views_decorator_file_cache($decorated_def, $decorator_def);
+
+        // Merge its data in.
+        $cache[$decorated_handler] = $decorated_def;
       }
-      // merge the new data in
-      $cache[$handler] = $def;
     }
   }
+
   return $cache;
 }
 
 /**
+ * Helper function for determining if a handler is other handler's ancestor.
+ */
+function _views_handler_is_ancestor_of($ancestor, $handler, $cache) {
+  while ($handler != $ancestor) {
+    if (isset($cache[$handler]['parent'])) {
+      $handler = $cache[$handler]['parent'];
+    }
+    else {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * Helper function for generating decorated handler's name.
+ */
+function views_handler_decorated_name($handler, $module) {
+  // '_handler_SUFIX'
+  if ($sufix = strstr($handler, '_handler')) {
+    // 'PREFIX'
+    $prefix = substr($handler, 0, strpos($handler, '_handler'));
+    if ($prefix == 'views') {
+      // 'module_handler_SUFIX'
+      return $module . $sufix;
+    } else {
+      // 'module_PREFIX_handler_SUFIX'
+      return $module .'_'. $prefix . $sufix;
+    }
+  } else {
+    return false;
+  }
+}
+
+/**
+ * A static file cache for "decorators".
+ *
+ * Because of the capabilities of PHP we have to do some tricks to achieve
+ * something what we can call "horizontal extensibility". We chose generating of files,
+ * because in this case we don't need to do it on every page request. That is
+ * therefore faster than using complicated implementations of the Decorator design
+ * pattern hacked with magic methods :) maybe :)
+ *
+ * Generated files are being saved to the folder
+ * 'sites/www.example.com/files/views'. They are purged within a cache clear.
+ */
+function _views_decorator_file_cache($decorated_def, $decorator_def) {
+  $decorated_filename = './' . $decorated_def['path'] . '/' . $decorated_def['file'];
+  if (!file_exists($decorated_filename)) {
+    // Create the cache directory if it not exist.
+    file_check_directory($decorated_def['path'], FILE_CREATE_DIRECTORY);
+
+    // Load decorator class "code template" and modify it before saving.
+    $decorator_filename = './' . $decorator_def['path'] . '/' . $decorator_def['file'];
+    $decorated_code = file_get_contents($decorator_filename);
+    $decorated_code = str_replace('class ' . $decorator_def['handler'] . ' extends ' . $decorator_def['parent'], 'class ' . $decorated_def['handler'] . ' extends ' . $decorated_def['parent'], $decorated_code);
+
+    // Save decorated code to a cache file.
+    if (!file_save_data($decorated_code, $decorated_filename, FILE_EXISTS_REPLACE)) {
+      vpr(t('Cannot write cache file.'));
+    }
+  }
+}
+
+/**
  * Fetch a handler to join one table to a primary table from the data cache
  */
 function views_get_table_join($table, $base_table) {
