--- nodereference.module.cvs 2006-08-21 11:02:42.000000000 +0200 +++ nodereference.module 2006-08-24 15:51:58.690643400 +0200 @@ -23,8 +23,13 @@ function nodereference_menu($may_cache) $items = array(); if ($may_cache) { - $items[] = array('path' => 'nodereference/autocomplete', 'title' => t('node reference autocomplete'), - 'callback' => 'nodereference_autocomplete', 'access' => user_access('access content'), 'type' => MENU_CALLBACK); + $items[] = array( + 'path' => 'nodereference/autocomplete', + 'title' => t('node reference autocomplete'), + 'callback' => 'nodereference_autocomplete', + 'access' => user_access('access content'), + 'type' => MENU_CALLBACK, + ); } return $items; @@ -35,7 +40,8 @@ function nodereference_menu($may_cache) */ function nodereference_field_info() { return array( - 'nodereference' => array('label' => 'Node Reference'), + 'nodereference' => array('label' => t('Node Reference')), + 'nodereferrers' => array('label' => t('Node Referrers')), ); } @@ -43,8 +49,8 @@ function nodereference_field_info() { * Implementation of hook_field_settings(). */ function nodereference_field_settings($op, $field) { - switch ($op) { - case 'form': + switch ($field['type'] .'/'. $op) { + case 'nodereference/form': $form = array(); $form['referenceable_types'] = array( '#type' => 'checkboxes', @@ -55,27 +61,80 @@ function nodereference_field_settings($o ); return $form; - case 'save': + case 'nodereference/save': return array('referenceable_types'); - case 'database columns': + case 'nodereferrers/form': + $form = array(); + $form['referrer_types'] = array( + '#type' => 'checkboxes', + '#title' => t('Referrer types to be displayed in list.'), + '#multiple' => TRUE, + '#default_value' => isset($field['referrer_types']) ? $field['referrer_types'] : array(), + '#options' => node_get_types(), + ); + return $form; + + case 'nodereferrers/save': + return array('referrer_types'); + + case 'nodereference/database columns': + case 'nodereferrers/database columns': $columns = array( 'nid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'), ); return $columns; + } } /** * Implementation of hook_field(). */ -function nodereference_field($op, &$node, $field, &$items, $teaser, $page) { - switch ($op) { - case 'view': - foreach ($items as $delta => $item) { - $items[$delta]['view'] = content_format($field, $item, 'default', $node); +function nodereference_field($op, &$node, $field, &$node_field, $teaser, $page) { + switch ($field['type'] .'/'. $op) { + case 'nodereference/view': + foreach ($node_field as $delta => $item) { + $node_field[$delta]['view'] = nodereference_field_view_item($field, $item); + } + return theme('field', $node, $field, $node_field, $teaser, $page); + + case 'nodereferrers/view': + // Pass referring node objects to nodereference theming and + // pass the *array* of themed views to content theme_field(). 24/08/2006 sun + $output = array(); + foreach ($node_field as $delta => $item) { + $output[$delta]['view'] = theme('nodereference', $field, $item); + } + return theme('field', $node, $field, $output, $teaser, $page); + + case 'nodereferrers/insert': + // Assign the node's nid to the referrers data. This helps retrieving the node's referrers. + // Needless, but I don't know where else this is used. 24/08/2006 sun + $node_field[0]['nid'] = $node->nid; + return; + + case 'nodereferrers/load': + $types = array_values($field['referrer_types']); + $values = nodereference_get_referrers($node->nid, $types); + + // $node_field contains the displayed node id currently. The whole column + // field__nid is needless, since we always have $node->nid. 24/08/2006 sun + + // Pass referring node objects into CCK content_load() cache. 24/08/2006 sun + $node_field = array(); + foreach ($values as $nid => $rnode) { + $node_field[] = $rnode; } - return theme('field', $node, $field, $items, $teaser, $page); + return array($field['field_name'] => $node_field); + + case 'nodereference/update': + case 'nodereferrers/update': + // clear cache for referring nodes to update their views + foreach (nodereference_get_referrers($node->nid) as $delta => $item) { + cache_clear_all('content:'. $item->nid .':'. $item->vid); + } + return; } } @@ -117,18 +176,49 @@ function nodereference_field_formatter($ } /** + * Implementation of hook_field_view_item(). + * Has to be moved to hook_field_formatter() 24/08/2006 sun + */ +function nodereference_field_view_item($field, $item) { + if (!isset($item['nid'])) { + return ''; + } + + switch($field['type']) { + case 'nodereference': + $referenced_node = node_load($item['nid']); + if ($referenced_node) { + return theme('nodereference', $field, $referenced_node); + } + break; + + case 'nodereferrers': + // Should/could these be retrieved on hook_field($op='load')? + $referrers = nodereference_get_referrers($item['nid']); + foreach($referrers as $referrer) { + $output .= theme('nodereference', $field, $referrer); + } + return $output; + } +} + +/** * Implementation of hook_widget_info(). */ function nodereference_widget_info() { return array( 'nodereference_select' => array( - 'label' => 'Select List', + 'label' => t('Select List'), 'field types' => array('nodereference'), ), 'nodereference_autocomplete' => array( - 'label' => 'Autocomplete Text Field', + 'label' => t('Autocomplete Text Field'), 'field types' => array('nodereference'), ), + 'nodereferrers_list' => array( + 'label' => t('Read-Only List'), + 'field types' => array('nodereferrers'), + ), ); } @@ -136,120 +226,125 @@ function nodereference_widget_info() { * Implementation of hook_widget(). */ function nodereference_widget($op, &$node, $field, &$node_field) { - if ($field['widget']['type'] == 'nodereference_select') { - switch ($op) { - case 'prepare form values': - $node_field_transposed = content_transpose_array_rows_cols($node_field); - $node_field['default nids'] = $node_field_transposed['nid']; - break; - - case 'form': - $form = array(); - - $form[$field['field_name']] = array('#tree' => TRUE); - $form[$field['field_name']]['nids'] = array( - '#type' => 'select', - '#title' => t($field['widget']['label']), - '#default_value' => $node_field['default nids'], - '#multiple' => $field['multiple'], - '#options' => _nodereference_potential_references($field), - '#required' => $field['required'], - '#description' => $field['widget']['description'], - ); - - return $form; + switch($field['widget']['type'] .'/'. $op) { + case 'nodereference_select/prepare form values': + $node_field_transposed = content_transpose_array_rows_cols($node_field); + $node_field['default nids'] = $node_field_transposed['nid']; + break; - case 'process form values': - if ($field['multiple']) { - $node_field = content_transpose_array_rows_cols(array('nid' => $node_field['nids'])); - } - else { - $node_field[0]['nid'] = $node_field['nids']; - } - // Remove the widget's data representation so it isn't saved. - unset($node_field['nids']); - } - } - else { - switch ($op) { - case 'prepare form values': - foreach ($node_field as $delta => $item) { - $node_field[$delta]['default node_name'] = db_result(db_query(db_rewrite_sql('SELECT n.title FROM {node} n WHERE n.nid = %d'), $node_field[$delta]['nid'])); - } - break; + case 'nodereference_select/form': + $form = array(); + $form[$field['field_name']] = array('#tree' => TRUE); + $form[$field['field_name']]['nids'] = array( + '#type' => 'select', + '#title' => t($field['widget']['label']), + '#default_value' => $node_field['default nids'], + '#multiple' => $field['multiple'], + '#options' => _nodereference_potential_references($field), + '#required' => $field['required'], + '#description' => $field['widget']['description'], + ); + return $form; - case 'form': - $form = array(); - $form[$field['field_name']] = array('#tree' => TRUE); - - if ($field['multiple']) { - $form[$field['field_name']]['#type'] = 'fieldset'; - $form[$field['field_name']]['#title'] = t($field['widget']['label']); - $form[$field['field_name']]['#description'] = $field['widget']['description']; - $delta = 0; - foreach ($node_field as $item) { - if ($item['nid']) { - $form[$field['field_name']][$delta]['node_name'] = array( - '#type' => 'textfield', - '#title' => '', - '#autocomplete_path' => 'nodereference/autocomplete/'. $field['field_name'], - '#default_value' => $item['default node_name'], - '#required' => ($delta == 0) ? $field['required'] : FALSE, - ); - $delta++; - } - } - foreach (range($delta, $delta + 2) as $delta) { + case 'nodereference_select/process form values': + if ($field['multiple']) { + $node_field = content_transpose_array_rows_cols(array('nid' => $node_field['nids'])); + } + else { + $node_field[0]['nid'] = $node_field['nids']; + } + // Remove the widget's data representation so it isn't saved. + unset($node_field['nids']); + break; + + case 'nodereference_autocomplete/prepare form values': + foreach ($node_field as $delta => $item) { + $node_field[$delta]['default node_name'] = db_result(db_query(db_rewrite_sql('SELECT n.title FROM {node} n WHERE n.nid = %d'), $node_field[$delta]['nid'])); + } + break; + + case 'nodereference_autocomplete/form': + $form = array(); + $form[$field['field_name']] = array('#tree' => TRUE); + if ($field['multiple']) { + $form[$field['field_name']]['#type'] = 'fieldset'; + $form[$field['field_name']]['#title'] = t($field['widget']['label']); + $form[$field['field_name']]['#description'] = $field['widget']['description']; + $delta = 0; + foreach ($node_field as $item) { + if ($item['nid']) { $form[$field['field_name']][$delta]['node_name'] = array( '#type' => 'textfield', '#title' => '', '#autocomplete_path' => 'nodereference/autocomplete/'. $field['field_name'], - '#default_value' => '', + '#default_value' => $item['default node_name'], '#required' => ($delta == 0) ? $field['required'] : FALSE, ); + $delta++; } } - else { - $form[$field['field_name']][0]['node_name'] = array( + foreach (range($delta, $delta + 2) as $delta) { + $form[$field['field_name']][$delta]['node_name'] = array( '#type' => 'textfield', - '#title' => t($field['widget']['label']), + '#title' => '', '#autocomplete_path' => 'nodereference/autocomplete/'. $field['field_name'], - '#default_value' => $node_field[0]['default node_name'], - '#required' => $field['required'], - '#description' => $field['widget']['description'], + '#default_value' => '', + '#required' => ($delta == 0) ? $field['required'] : FALSE, ); } - return $form; + } - case 'validate': - foreach ($node_field as $delta => $item) { - if ($item['node_name'] && !in_array($item['node_name'], _nodereference_potential_references($field))) { - form_set_error($field['field_name'], t('No post with that title exists.')); - } + else { + $form[$field['field_name']][0]['node_name'] = array( + '#type' => 'textfield', + '#title' => t($field['widget']['label']), + '#autocomplete_path' => 'nodereference/autocomplete/'. $field['field_name'], + '#default_value' => $node_field[0]['default node_name'], + '#required' => $field['required'], + '#description' => $field['widget']['description'], + ); + } + return $form; + + case 'nodereference_autocomplete/validate': + foreach ($node_field as $delta => $item) { + if ($item['node_name'] && !in_array($item['node_name'], _nodereference_potential_references($field))) { + form_set_error($field['field_name'], t('No post with that title exists.')); } - return; + } + return; - case 'process form values': - foreach ($node_field as $delta => $item) { - $nid = 0; - if ($node_field[$delta]['node_name']) { - $nid = db_result(db_query(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.title = '%s'"), $node_field[$delta]['node_name'])); - } - // Remove the widget's data representation so it isn't saved. - unset($node_field[$delta]['node_name']); - if ($nid) { - $node_field[$delta]['nid'] = $nid; - } - else { - unset($node_field[$delta]); - } + + + + case 'nodereference_autocomplete/process form values': + foreach ($node_field as $delta => $item) { + $nid = db_result(db_query(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.title = '%s'"), $node_field[$delta]['node_name'])); + + // Remove the widget's data representation so it isn't saved. + unset($node_field[$delta]['node_name']); + if ($nid) { + $node_field[$delta]['nid'] = $nid; } - break; - } + else { + unset($node_field[$delta]); + } + } + break; + + case 'nodereferrers_list/form': + $form = array(); + $form[$field['field_name']] = array('#tree' => TRUE); + $form[$field['field_name']][0]['nid'] = array( + '#type' => 'hidden', + '#value' => $node->nid, + ); + return $form; + + } } - /** * Fetch an array of all candidate referenced nodes, for use in presenting the selection form to the user. */ @@ -306,4 +401,47 @@ function nodereference_autocomplete($fie print drupal_to_js($matches); exit(); -} \ No newline at end of file +} + +/** + * get an array of referrers by nid and content type. + * @param nid + * referred to nodes nid + * @param content_types + * array of content types to be queried for. empty array == all content types + * @return array + */ +function nodereference_get_referrers($nid, $content_types = array()) { + // Filter all content fields to find names of all fields of type nodereference + $fields = content_fields(); + $values = array(); + foreach($fields as $field) { + if ($field['type'] == 'nodereference') { + $db_info = content_database_info($field); + + // Gather nodereferences that refer to $nid + // Fetch only nid and title from nodes for output and vid for caching 24/08/2006 sun + $filter_content_types = ''; + if ($content_types) { + $filter_content_types = 'AND n.type IN ('". implode("', '", $content_types) ."') '; + } + $result = db_query( + "SELECT n.nid, n.vid, n.title + FROM {" . $db_info['table'] . "} nr + INNER JOIN {node} n ON n.vid = nr.vid AND n.status = 1 ". $filter_content_types ." + WHERE nr." . $db_info['columns']['nid']['column'] . " = %d + ORDER BY n.created DESC", $nid); + + while ($value = db_fetch_object($result)) { + // avoid duplicate referrers by using nid as key + $values[$value->nid] = $value; + } + } + } + return $values; +} + + +function theme_nodereference($field, $node) { + return '
'. l($node->title, 'node/'. $node->nid) .'
'; +}