Index: composite.node.inc
===================================================================
--- composite.node.inc	(revision 1078)
+++ composite.node.inc	(working copy)
@@ -1,57 +1,110 @@
 <?php
 // $Id: composite.node.inc,v 1.1.2.3 2009/03/03 00:39:05 bengtan Exp $
 
+/**
+ * Check node exists. Replacement for node_load() in case of possible
+ * recursion. 
+ * 
+ * @param object|int $node
+ *   Node or nid to check existence.
+ * 
+ * @return boolean
+ */
+function _composite_node_exists($node) {
+  $nid = is_object($node) ? $node->nid : $node;
+  return (bool) db_result(db_query("SELECT 1 FROM {node} WHERE nid = %d", $nid));
+}
 
+/**
+ * Display a warning about deleted nodes.
+ */
+function _composite_node_warning($node = NULL) {
+  static $displayed = FALSE;
+  $access = FALSE;
+  // If no composite node given, check if user has the abstract composite
+  // permission.
+  if (! $node && user_access('edit composite layouts')) {
+    $access = TRUE;
+  }
+  // Else check for the node only.
+  else if (composite_access(NULL, 'update', $node)) {
+    $access = TRUE;
+  }
+  // Display the message only once.
+  if (! $displayed && $access) {
+    drupal_set_message(t("Deleted node(s) have been detected on this layout. Please at least update it to remove void references."), 'error');
+    $displayed = TRUE;
+  }
+}
+
 function composite_composite_node_api(&$reference, $op, $a3 = NULL, $a4 = NULL) {
   global $language;
   
   switch ($op) {
     // Derive additional fields 
     case 'load':
-      // Note: can't do a node_load here, otherwise, we run the chance of an infinite loop. 
-      list($unused, $reference['nid']) = explode('-', $reference['id'], 2);
+      // Note: can't do a node_load here, otherwise, we run the chance of an infinite loop.
+      $parts = explode('-', $reference['id'], 2);
+      if (_composite_node_exists($parts[1])) { 
+        list($unused, $reference['nid']) = $parts[1];
+      }
+      else {
+        _composite_node_warning($a3);
+        $reference = NULL;
+      }
       break;
 
     // Generate and insert an informative human-readable string into ['info']
     case 'info':
-      $node = node_load($reference['nid']);
-      $reference['info'] = check_plain($node->title);
+      if ($node = node_load($reference['nid'])) {
+        $reference['info'] = check_plain($node->title);
+      }
+      else {
+        _composite_node_warning($a3);
+        $reference = NULL;
+      }
       break;
 
     // Return a rendering of the reference item
     case 'view':
-      $node = node_load($reference['nid']);
-      
-      // check if node has a translation, if yes, set the translation in the current language as $node
-      if ($node->tnid) {
-        $translations = translation_node_get_translations($node->tnid);
-        $node = node_load($translations[$language->language]->nid);
-      }
-    
-      if ($node->nid && node_access('view', $node)) {
-        switch ($reference['data']['format']) {
-          case 'title':
-            $output = theme('composite_node_title', check_plain($node->title));
-            break;
+      $output = '';
 
-          case 'title-link':
-            $output = theme('composite_node_title', l($node->title, 'node/' . $node->nid));
-            break;
+      if ($node = node_load($reference['nid'])) {
 
-          case 'teaser':
-            $output =  node_view($node, TRUE, FALSE);
-            break;
-
-          case 'full':
-            if (_composite_nodes_recursion_check($node)) {
-              drupal_set_message(t('You have created an infinite loop. One node is displaying a second node which in turn displays the first node.'), 'error');
+        // check if node has a translation, if yes, set the translation in the current language as $node
+        if ($node->tnid) {
+          $translations = translation_node_get_translations($node->tnid);
+          $node = node_load($translations[$language->language]->nid);
+        }
+      
+        if ($node->nid && node_access('view', $node)) {
+          switch ($reference['data']['format']) {
+            case 'title':
+              $output = theme('composite_node_title', check_plain($node->title));
+              break;
+  
+            case 'title-link':
+              $output = theme('composite_node_title', l($node->title, 'node/' . $node->nid));
+              break;
+  
+            case 'teaser':
               $output =  node_view($node, TRUE, FALSE);
-            }
-            else {
-              $output =  node_view($node, FALSE, FALSE);
-            }
-            break;
+              break;
+  
+            case 'full':
+              if (_composite_nodes_recursion_check($node)) {
+                drupal_set_message(t('You have created an infinite loop. One node is displaying a second node which in turn displays the first node.'), 'error');
+                $output =  node_view($node, TRUE, FALSE);
+              }
+              else {
+                $output =  node_view($node, FALSE, FALSE);
+              }
+              break;
+          }
         }
+        else {
+          _composite_node_warning($a3);
+        }
         return $output;
       }
       break;
