'Nodereference graph', 'page callback' => 'graphviz_noderef_page', 'page arguments' => array(1), 'access arguments' => array('access Graphviz Noderef display'), 'type' => MENU_LOCAL_TASK, ); return $items; } function graphviz_noderef_page($node) { $tree = graphviz_noderef_get_ref_array((int)$node->nid, 0); $dot = graphviz_noderef_ref_array_to_dot($tree[0], $tree[1]); $output = graphviz_filter_process($dot); return $output; } /** * Custom functions for gathering and formatting data. * **/ function graphviz_noderef_ref_array_to_dot(array $flat_array, array $parameters = array(), array $headers = array(), array $style = array()) { //initialize output $output = ""; //print headers $output .= graphviz_noderef_headers_to_dot($headers); //convert the parameters to dot format. $output .= graphviz_noderef_params_to_dot($parameters); //convert links array to dot format links $link_array = array(); foreach ($flat_array as $link){ $nid = $link['nid']; $ref = $link['ref']; if ($link['type'] == "nodereference") { $action = str_replace(array("field_","_"),array(""," "), $link['field']); $link_array[] .= "\t$nid -> $ref [ label = \"$action\" ];\n"; } elseif ($link['type'] == "nodereferrer"){ $action = str_replace(array("field_","_"),array(""," "), $link['referrer']); $link_array[] .= "\t$ref -> $nid [ label = \"$action\" ];\n"; } } $output .= join(array_unique($link_array)); //print end $output .="};"; return $output; } function graphviz_noderef_headers_to_dot(array $options = array() ) { $defaults = array('command' => "dot", 'formats' => "png", 'imagemap' => true); $headers = array_merge($options,$defaults); $output = "/*\n"; foreach ($headers as $key => $value) { switch ($key) { case 'command': $output .= "* @command = $value\n"; break; case 'formats': $output .= "* @formats = $value\n"; break; case 'imagemap': $output .= "* @imagemap = " . ( ($value == true) ? "true" : "false" ) . "\n"; break; } } $output .= "*/\ndigraph NodeRefMap {\n"; $output .= "\tgraph [];\n"; $output .= "\tnode [ fontsize=10.0];\n"; $output .= "\tedge [ color=\"lightgrey\", penwidth=3, fontsize=9.0];\n"; return $output; } function graphviz_noderef_params_to_dot(array $parameters = array()) { $output = ""; foreach ($parameters as $nid => $data) { $shape = ($data['type'] == "organisation") ? "box" : "ellipse"; $url = "node/". $nid; $output .= "\t$nid [ shape = \"$shape\" label = \"". $data['title'] . "\" URL = \"/drupal6/node/". $nid."\" ];\n"; } return $output; } function graphviz_noderef_get_ref_array($nid, $recursion_depth = 2, array $checked_nodes = array()) { // don't be stupid - first two arguments must be int >= 1 if ( !is_int($nid) ) { return "Error: your nid argument is not an integer";} if ($nid <= 0 ) { return "Error: your nid argument is $nid";} if ( !is_int($recursion_depth) ) { return "Error: Your recursion depth is not an integer.";} if ( $recursion_depth < 0 ) { return "Error: Your recursion depth is less than 0";} if ( in_array( $nid , array_keys($checked_nodes) ) ) { return "Node $nid has already been checked"; } $node = node_load($nid); //initialise arrays $references = array(); $referrers = array(); $fields = array(); $nids_to_check = array(); //get all custom fields of type referrer/reference $result_fields = db_query( "SELECT field_name, type FROM {content_node_field} WHERE type = '%s' OR type = '%s' " , "nodereference", "nodereferrer"); while ($row = db_fetch_object($result_fields)) { $fields[] = array('name' => $row->{"field_name"}, 'type' =>$row->{"type"}); } //loop over all possible reference/referrer fields, and add any that exist to apporopriate array foreach($fields as $field) { $field_name = $field['name']; if (is_array($node->$field_name) && count($node->$field_name) > 0){ if ($field['type'] == "nodereference") { foreach ($node->$field_name as $reference){ if ( (int)($reference['nid']) != 0 ) { $references[] = array('nid' => $nid, 'type' => $field['type'], 'field' => $field_name, 'ref' => (int)($reference['nid']) ); $nids_to_check[] = $reference['nid']; } } } elseif ($field['type'] == "nodereferrer"){ $ref_field = $node->$field_name; foreach ($ref_field[0]['items'] as $referrer) { $referrers[] = array('nid' => $nid, 'type' => $field['type'], 'field' => $field_name, 'ref' => (int)$referrer['nid'], 'referrer' => $referrer['referrer']); $nids_to_check[] = $referrer['nid']; } } else { return "Error: \$field['name'] is bad: " . $field['name']; } } } //stick $references and referrers in array together $node_ref_links = array_merge($references, $referrers); // dprint_r($node_ref_links); //add checked node to array to pass if ( !in_array($nid, array_keys($checked_nodes))){ $checked_nodes["$nid"] = array ( 'title' => $node->title, 'type' => $node->type, 'name' => $node->title, 'depth' => $recursion_depth ); $checked_nodes["$nid"]['count'] = 1; } else { $checked_nodes["$nid"]['count'] += 1; } //reduce recursion depth $recursion_depth -= 1; //initialise $return_array $return_array = array(); //RECURSE - need to check checked_nodes! //only if recursion level still high enough if ($recursion_depth >= 0 ) { foreach ($node_ref_links as $node_ref) { //make sure that node hasn't already been checked. if ( in_array( $node_ref['ref'], array_keys($checked_nodes) ) ) { //dprint_r( "Node ". $node_ref['ref'] . " has already been checked."); } else { //append results $recursion_results = graphviz_noderef_get_ref_array($node_ref['ref'], $recursion_depth, $checked_nodes); $return_array = array_merge($node_ref_links, $recursion_results[0]); $checked_nodes = $checked_nodes + $recursion_results[1] ; } } } else { //if we've finished recursing, we still need to check the last nodes for title, url, etc. $return_array = $node_ref_links; foreach ($nids_to_check as $nid) { if ( !in_array($nid, array_keys($checked_nodes) ) ) { $node = node_load($nid); $checked_nodes["$nid"] = array ( 'title' => $node->title, 'type' => $node->type, 'name' => $node->title, 'depth' => $recursion_depth ); $checked_nodes["$nid"]['count'] = 1; } } } return array( $return_array, $checked_nodes ); }