/[drupal]/contributions/modules/fieldreference/fieldreference.module
ViewVC logotype

Diff of /contributions/modules/fieldreference/fieldreference.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph | View Patch Patch

revision 1.2.2.1, Tue May 13 21:28:25 2008 UTC revision 1.2.2.2, Tue Jun 17 15:07:55 2008 UTC
# Line 1  Line 1 
1  <?php  <?php
2  // $Id: fieldreference.module,v 1.2 2008/05/02 20:13:00 deekayen Exp $  // $Id: fieldreference.module,v 1.6 2008/06/16 14:49:24 guardian Exp $
3    
4  /**  /**
5   * @file   * @file
# Line 40  function fieldreference_field_info() { Line 40  function fieldreference_field_info() {
40  function fieldreference_field_settings($op, $field) {  function fieldreference_field_settings($op, $field) {
41    switch ($op) {    switch ($op) {
42      case 'form':      case 'form':
43        return fieldreference_field_formtable($field);        $form = array();
44          $form['referenceable_types'] = array(
45            '#type' => 'checkboxes',
46            '#title' => t('Fields  that can be referenced'),
47            '#multiple' => TRUE,
48            '#default_value' => isset($field['referenceable_types']) ? $field['referenceable_types'] : array(),
49            '#options' => _fieldreference_get_fields()
50          );
51          return $form;
52    
53      case 'save':      case 'save':
54        return array('referenceable_types');        return array('referenceable_types');
55    
56      case 'database columns':      case 'database columns':
57        $columns = array(        $columns = array(
58          'cfn' => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE),          'nid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'),
59            'field_name' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => "''"),
60            'delta' => array('type' => 'int', 'not null' => TRUE, 'default' => '0')
61        );        );
62        return $columns;        return $columns;
   }  
 }  
   
 function fieldreference_field_formtable($field) {  
   $form = array();  
   
   $form['fieldreference fields'] = array(  
     '#title' => t('Fields that can be referenced'),  
     '#type' => 'fieldset',  
     '#collapsible' => TRUE,  
     '#collapsed' => FALSE  
   );  
   
   $fieldreference_list = _fieldreference_get_fields();  
   foreach ($fieldreference_list as $ref) {  
     $fields[$ref->type .':'. $ref->field_name] = '';  
     $form['fieldreference fields']['content_name'][$ref->type .':'. $ref->field_name] = array(  
       '#type' => 'markup',  
       '#value' => $ref->name  
     );  
     $form['fieldreference fields']['field_label'][$ref->type .':'. $ref->field_name] = array(  
       '#type' => 'markup',  
       '#value' => $ref->label  
     );  
   }  
   unset($fieldreference_list, $ref);  
   
   $form['fieldreference fields']['referenceable_fields_header'] = array(  
     '#type' => 'value',  
     '#value' => array(  
       array('data' => ''),  
       array('data' => t('Content type')),  
       array('data' => t('Field'))  
       )  
   );  
   $form['fieldreference fields']['referenceable_fields'] = array(  
     '#type' => 'checkboxes',  
     '#default_value' => isset($field['referenceable_fields']) ? $field['referenceable_fields'] : array(),  
     '#options' => $fields  
   );  
   $form['#theme'] = 'fieldreference_field_formtable';  
   return $form;  
 }  
63    
64  function theme_fieldreference_field_formtable($form) {        case 'filters':
65    $rows = array();          return array(
66    foreach (element_children($form['fieldreference fields']['content_name']) as $key) {            'default' => array(
67      $row = array();            'list' => '_fieldreference_filter_handler',
68      $row['data'][0] = drupal_render($form['fieldreference fields']['referenceable_fields'][$key]);            'list-type' => 'list',
69      $row['data'][1] = drupal_render($form['fieldreference fields']['content_name'][$key]);            'operator' => 'views_handler_operator_or',
70      $row['data'][2] = drupal_render($form['fieldreference fields']['field_label'][$key]);            'value-type' => 'array',
71      $row['data'][3] = drupal_render($form['fieldreference fields']['field_label'][$key]);            'extra' => array('field' => $field),
72      $rows[] = $row;          ),
73          );
74    }    }
   
   $form['fieldreference fields']['fields list'] = array(  
     '#value' => theme('table', $form['fieldreference fields']['referenceable_fields_header']['#value'], $rows)  
   );  
   $output = drupal_render($form);  
   return $output;  
75  }  }
76    
77  /**  /**
78   * Return an array of all fields   * Return an array of all fields
79   */   */
80  function _fieldreference_get_fields() {  function _fieldreference_get_fields() {
81    $fields_list = array();    $fields = array();
82    $result = db_query('SELECT    $result = db_query('SELECT nt.type, nfi.field_name, nt.name, nfi.label
83        nt.type, nfi.field_name, nt.name, nfi.label                        FROM {node_type} nt INNER JOIN {node_field_instance} nfi ON nt.type = nfi.type_name
84      FROM                        ORDER BY nt.name, nfi.label');
85        {node_type} AS nt INNER JOIN {node_field_instance} AS nfi ON nt.type = nfi.type_name  
86      ORDER BY    while ($row = db_fetch_object($result)) {
87        nt.name, nfi.label');      $fields[$row->type . ':' . $row->field_name] = $row->name . ':' . $row->label;
   while ($obj = db_fetch_object($result)) {  
     $fields_list[] = $obj;  
88    }    }
89    return $fields_list;  
90      return $fields;
91  }  }
92    
93  /**  /**
# Line 134  function _fieldreference_get_fields() { Line 95  function _fieldreference_get_fields() {
95   */   */
96  function fieldreference_field($op, &$node, $field, &$items, $teaser, $page) {  function fieldreference_field($op, &$node, $field, &$items, $teaser, $page) {
97    switch ($op) {    switch ($op) {
98      case 'view':      case 'validate':
99          $refs = array_keys(_fieldreference_potential_references($field));
100          $fields = array_values($items['fields']);
101          unset($items['fields']);
102        foreach ($items as $delta => $item) {        foreach ($items as $delta => $item) {
103          $items[$delta]['view'] = content_format($field, $item, 'default', $field);          $error_field = isset($item['error_field']) ? $item['error_field'] : '';
104            unset($item['error_field']);
105            if (!empty($fields[$delta])) {
106              if (!in_array($fields[$delta], $refs)) {
107                form_set_error($error_field, t('%name : This field can\'t be referenced.', array('%name' => t($field['widget']['label']))));
108              }
109            }
110        }        }
111        return theme('field', $field, $field, $items, $teaser, $page);        return;
112    
113        default:
114          unset($items['fields']);
115    }    }
116  }  }
117    
# Line 149  function fieldreference_field_formatter_ Line 122  function fieldreference_field_formatter_
122    return array(    return array(
123      'default' => array(      'default' => array(
124        'label' => 'Default',        'label' => 'Default',
125        'field types' => array('fieldreference'),        'field types' => array('fieldreference')
126      ),      ),
127      'plain' => array(      'full' => array(
128        'label' => 'Plain text',        'label' => t('Full'),
129        'field types' => array('fieldreference'),        'field types' => array('fieldreference')
130      ),      ),
131        'teaser' => array(
132          'label' => t('Teaser'),
133          'field types' => array('fieldreference')
134        )
135    );    );
136  }  }
137    
138  /**  /**
139   * Implementation of hook_field_formatter().   * Implementation of hook_field_formatter().
140   */   */
141  function fieldreference_field_formatter($field, $item, $formatter, $field) {  function fieldreference_field_formatter($field, $item, $formatter, $node) {
142    $text = '';    static $recursion_queue = array();
143    $fields = array();  
144    if (isset($item['cfn'])) {    if (empty($item['nid']) || !is_numeric($item['nid']) ||
145      $fieldreference_list = _fieldreference_get_fields();        empty($item['field_name']) ||
146      foreach ($fieldreference_list as $field) {        !is_numeric($item['delta'])) {
147        $fields[$field->type .':'. $field->field_name] = $field->name .':'. $field->label;      return '';
     }  
     $referenced_field = $fields[$item['cfn']];  
     if ($referenced_field) {  
       $text = $referenced_field;  
     }  
148    }    }
149    
150    switch ($formatter) {    $field_id = $item['nid'] . ':' . $item['field_name'] . ':' . $item['delta'];
151      case 'plain':    if (in_array($field_id, $recursion_queue)) {
152        return strip_tags($text);      drupal_set_message(t('circular field reference chain'), 'error');
153        return '';
154      }
155    
156      if ($formatter == 'default') {
157        $context = $node->teaser ? 'teaser' : 'full';
158      }
159      else {
160        $context = $formatter;
161      }
162    
163      default:    $referenced_node = node_load($item['nid']);
164        return $text;    if (!isset($referenced_node->$item['field_name'])) {
165        return '';
166      }
167    
168      $referenced_type = content_types($node->type);
169      $referenced_field = $referenced_type['fields'][$item['field_name']];
170    
171      if ($referenced_field['type'] == 'fieldreference') {
172        $recursion_queue[] = $field_id;
173      }
174      else {
175        $recursion_queue = array();
176    }    }
177    
178      $referenced_formatter = isset($referenced_field['display_settings'][$context]['format']) ? $referenced_field['display_settings'][$context]['format'] : 'default';
179    
180      $referenced_items = $referenced_node->$item['field_name'];
181    
182      return content_format($referenced_field, $referenced_items[$item['delta']], $referenced_formatter, $referenced_node);
183  }  }
184    
185  /**  /**
# Line 192  function fieldreference_widget_info() { Line 190  function fieldreference_widget_info() {
190      'fieldreference_select' => array(      'fieldreference_select' => array(
191        'label' => 'Select List',        'label' => 'Select List',
192        'field types' => array('fieldreference'),        'field types' => array('fieldreference'),
193        ),
194        'fieldreference_autocomplete' => array(
195          'label' => t('Autocomplete Text Field'),
196          'field types' => array('fieldreference')
197      )      )
198    );    );
199  }  }
# Line 199  function fieldreference_widget_info() { Line 201  function fieldreference_widget_info() {
201  /**  /**
202   * Implementation of hook_widget().   * Implementation of hook_widget().
203   */   */
204  function fieldreference_widget($op, &$node, $field, &$field_field) {  function fieldreference_widget($op, &$node, $field, &$items) {
205    if ($field['widget']['type'] == 'fieldreference_select') {    if ($field['widget']['type'] == 'fieldreference_select') {
206      switch ($op) {      switch ($op) {
207        case 'prepare form values':        case 'prepare form values':
208          $field_field_transposed = content_transpose_array_rows_cols($field_field);          $options = array();
209          $field_field['default cfns'] = $field_field_transposed['cfn'];          foreach($items as $delta => $item) {
210              $options[] = $item['nid'] . ':' . $item['field_name'] . ':' . $item['delta'];
211            }
212            $items['default fields'] = $options;
213          break;          break;
214    
215        case 'form':        case 'form':
216          $form = array();          $form = array();
         $fields = array();  
   
         $form[$field['field_name']] = array('#tree' => TRUE);  
217    
218          $fieldreference_list = _fieldreference_get_fields();          $options = _fieldreference_potential_references($field);
219          foreach ($fieldreference_list as $ref) {          foreach ($options as $key => $value) {
220            $fields[$ref->type .':'. $ref->field_name] = $ref->name .':'. $ref->label;            $options[$key] = _fieldreference_item($field, $value, FALSE);
221          }          }
222          unset($fieldreference_list, $ref);          if (!$field['required']) {
223              $options = array(0 => t('<none>')) + $options;
224          $form[$field['field_name']]['cfns'] = array(          }
225            $form[$field['field_name']] = array('#tree' => TRUE);
226            $form[$field['field_name']]['fields'] = array(
227            '#type' => 'select',            '#type' => 'select',
228            '#title' => t($field['widget']['label']),            '#title' => t($field['widget']['label']),
229            '#default_value' => $field_field['default cfns'],            '#default_value' => $items['default fields'],
230            '#multiple' => $field['multiple'],            '#multiple' => $field['multiple'],
231            '#options' => $fields,            '#size' =>  $field['multiple'] ? min(count($options), 6) : 0,
232              '#options' => $options,
233            '#required' => $field['required'],            '#required' => $field['required'],
234            '#description' => $field['widget']['description'],            '#description' => t($field['widget']['description']),
235          );          );
236    
237          return $form;          return $form;
238    
239        case 'process form values':        case 'process form values':
240          if ($field['multiple']) {          if ($field['multiple']) {
241            $field_field = content_transpose_array_rows_cols(array('cfn' => $field_field['cfns']));            // if nothing selected, make it 'none'
242              if (empty($items['fields'])) {
243                $items['fields'] = array(0 => '0');
244              }
245              // drop the 'none' options if other items were also selected
246              elseif (count($items['fieds']) > 1) {
247                unset($items['nids'][0]);
248              }
249    
250              $storage = array();
251              foreach($items['fields'] as $value) {
252                $value = explode(':', $value);
253                if (!$value) {
254                  continue;
255                }
256                $delta['nid'] = $value[0];
257                $delta['field_name'] = $value[1];
258                $delta['delta'] = $value[2];
259                $delta['error_field'] =  $field['field_name'] .'][fields';
260                $storage[] = $delta;
261              }
262              $storage['fields'] = $items['fields'];
263              $items = $storage;
264            }
265            else {
266              $value = explode(':', $items['fields']);
267              if (!$value) {
268                unset($items[0]);
269              }
270              $items[0]['nid'] = $value[0];
271              $items[0]['field_name'] = $value[1];
272              $items[0]['delta'] = $value[2];
273              $items[0]['error_field'] =  $field['field_name'] .'][fields';
274            }
275            break;
276        }
277      }
278      else if ($field['widget']['type'] == 'fieldreference_autocomplete') {
279        switch($op) {
280          case 'prepare form values':
281            foreach ($items as $delta => $item) {
282              if (!empty($item['nid']) && !empty($item['field_name']) && is_numeric($item['delta'])) {
283                $query = "SELECT n.title AS title, nfi.label AS label FROM {node} n
284                          INNER JOIN {node_field_instance} nfi ON n.type = nfi.type_name
285                          WHERE n.nid = %d AND nfi.field_name = '%s'";
286                $result = db_fetch_object(db_query(db_rewrite_sql($query), $item['nid'], $item['field_name']));
287                $items[$delta]['default field'] = $result->title . ':' . $result->label . ':' . $item['delta'] . ' [' . implode(':', $item) . ']';
288              }
289            }
290            break;
291    
292          case 'form':
293            $form = array();
294            $form[$field['field_name']] = array('#tree' => TRUE);
295    
296            if ($field['multiple']) {
297              $form[$field['field_name']]['#type'] = 'fieldset';
298              $form[$field['field_name']]['#description'] = t($field['widget']['description']);
299              $delta = 0;
300              foreach ($items as $item) {
301                if (!empty($item['nid']) && !empty($item['field_name']) && is_numeric($item['delta'])) {
302                  $form[$field['field_name']][$delta]['field'] = array(
303                    '#type' => 'textfield',
304                    '#title' => ($delta == 0) ? t($field['widget']['label']) : '',
305                    '#autocomplete_path' => 'fieldreference/autocomplete/'. $field['field_name'],
306                    '#default_value' => $item['default field'],
307                    '#required' => ($delta == 0) ? $field['required'] : FALSE,
308                  );
309                  $delta++;
310                }
311              }
312              foreach (range($delta, $delta + 2) as $delta) {
313                $form[$field['field_name']][$delta]['field'] = array(
314                  '#type' => 'textfield',
315                  '#title' => ($delta == 0) ? t($field['widget']['label']) : '',
316                  '#autocomplete_path' => 'fieldreference/autocomplete/'. $field['field_name'],
317                  '#default_value' => '',
318                  '#required' => ($delta == 0) ? $field['required'] : FALSE,
319                );
320              }
321          }          }
322          else {          else {
323            $field_field[0]['cfn'] = $field_field['cfns'];            $form[$field['field_name']][0]['field'] = array(
324                '#type' => 'textfield',
325                '#title' => t($field['widget']['label']),
326                '#autocomplete_path' => 'fieldreference/autocomplete/'. $field['field_name'],
327                '#default_value' => $items[0]['default field'],
328                '#required' => $field['required'],
329                '#description' => t($field['widget']['description']),
330              );
331            }
332            return $form;
333    
334          case 'validate':
335            foreach ($items as $delta => $item) {
336              $error_field = $field['field_name'] .']['. $delta .'][field';
337              if (!empty($item['field'])) {
338                preg_match('/^(?:\s*|(.*)\s*:\s*(?:.*)\s*:\s*(?:\d+)\s+)?\[\s*(\d+)\s*:\s*([a-zA-Z0-9_\-]+)\s*:\s*(\d+)\s*\]$/', $item['field'], $matches);
339                if (!empty($matches)) {
340                  list(, $title, $nid, $field_name, $delta) = $matches;
341                  if (!empty($title) && ($n = node_load($nid)) && $title != $n->title) {
342                    form_set_error($error_field, t('%name : Title mismatch. Please check your selection.', array('%name' => t($field['widget']['label']))));
343                  }
344                }
345              }
346            }
347            return;
348    
349          case 'process form values':
350            $fields = array();
351            foreach ($items as $delta => $item) {
352              if (!empty($item['field'])) {
353                preg_match('/^(?:\s*|(.*)\s+)?\[\s*(\d+)\s*:\s*([a-zA-Z0-9_\-]+)\s*:\s*(\d+)\s*\]$/', $item['field'], $matches);
354                if (!empty($matches)) {
355                  list(, , $referenced_field_nid, $referenced_field_name, $referenced_field_delta) = $matches;
356                  $items[$delta]['nid'] = $referenced_field_nid;
357                  $items[$delta]['field_name'] = $referenced_field_name;
358                  $items[$delta]['delta'] = $referenced_field_delta;
359                  $items[$delta]['error_field'] = $field['field_name'] .']['. $delta .'][field';
360                  $fields[] = $referenced_field_nid . ':' . $referenced_field_name . ':' . $referenced_field_delta;
361                }
362                else {
363                  // TODO :
364                  // the best thing would be to present the user with an additional form,
365                  // allowing the user to choose between valid candidates with the same title
366                  // ATM, we pick the first matching candidate...
367                  $refs = _fieldreference_potential_references($field, $item['field'], TRUE);
368                  $referenced_field = (!empty($refs)) ? array_shift(array_values($refs)) : 0;
369                  if (!empty($referenced_field)) {
370                    $items[$delta]['nid'] = $referenced_field->nid;
371                    $items[$delta]['field_name'] = $referenced_field->name;
372                    $items[$delta]['delta'] = $referenced_field->delta;
373                    $items[$delta]['error_field'] = $field['field_name'] .']['. $delta .'][field';
374                    $fields[] = $referenced_field->nid . ':' . $referenced_field->name . ':' . $referenced_field->delta;
375                  }
376                  elseif ($delta > 0) {
377                    unset($items[$delta]);
378                  }
379                }
380                unset($items[$delta]['field']);
381              }
382              else {
383                unset($items[$delta]);
384              }
385            }
386            $items['fields'] = $fields;
387            break;
388        }
389      }
390    }
391    
392    /**
393     * Fetch an array of all candidate referenced fields, for use in presenting the selection form to the user.
394      */
395    function _fieldreference_potential_references($field, $string = '', $exact_string = FALSE) {
396      if (isset($field['referenceable_types'])) {
397        $sub_queries = array();
398        $args = array();
399        $i = 0;
400    
401        foreach($field['referenceable_types'] as $referenceable_type) {
402          if($referenceable_type) {
403            $referenceable_type = explode(':', $referenceable_type);
404            $type = $referenceable_type[0];
405            $field_name = $referenceable_type[1];
406    
407            $referenced_field = content_fields($field_name);
408            $db_info = content_database_info($referenced_field);
409            $sub_query = "(SELECT n.nid AS nid, n.title AS title, n.type AS type, '%s' AS name, '%s' AS label, " . ($referenced_field['multiple'] ? "t$i.delta" : "'0'") . " AS delta FROM {node} n INNER JOIN {%s} t$i ON n.nid = t$i.nid WHERE n.type = '%s'";
410    
411            $args[] = $field_name;
412            $args[] = $referenced_field['widget']['label'];
413            $args[] = $db_info['table'];
414            $args[] = $type;
415    
416            if (!empty($string)) {
417              $sub_query .= $exact_string ? " AND n.title = '%s'" : " AND n.title LIKE '%%%s%'";
418              $args[] = $string;
419          }          }
420          // Remove the widget's data representation so it isn't saved.  
421          unset($field_field['cfns']);          $sub_query .= ')';
422    
423            $sub_queries[] = $sub_query;
424            ++$i;
425          }
426        }
427    
428        $query = implode(' UNION ', $sub_queries) . " ORDER BY title, type, label, delta";
429        $result = db_query(db_rewrite_sql($query), $args);
430    
431        if (db_num_rows($result) == 0) {
432          return array();
433      }      }
434    
435        $rows = array();
436        while ($row = db_fetch_object($result)) {
437          $rows[$row->nid . ':' . $row->name . ':' . $row->delta] = $row;
438        }
439    
440        return $rows;
441    }    }
442    
443      return array();
444  }  }
445    
446  /**  /**
447   * Retrieve a pipe delimited string of autocomplete suggestions   * Retrieve a pipe delimited string of autocomplete suggestions
448   */   */
449  function fieldreference_autocomplete($field_name, $string = '') {  function fieldreference_autocomplete($field_name, $string = '') {
450    $fields = content_fields();    $field = content_fields($field_name);
   $field = $fields[$field_name];  
451    $matches = array();    $matches = array();
452    
453    foreach (_fieldreference_potential_references($field, TRUE, $string) as $row) {    foreach (_fieldreference_potential_references($field, $string) as $row) {
454      $matches[$row->node_title .' [nid:'. $row->nid .']'] = _fieldreference_item($field, $row);      $matches[$row->title . ':' . $row->label . ':' . $row->delta . ' [' . $row->nid . ':' . $row->name . ':' . $row->delta . ']'] = _fieldreference_item($field, $row);
455    }    }
456    
457    print drupal_to_js($matches);    print drupal_to_js($matches);
458    exit();    exit();
459  }  }
460    
461    function _fieldreference_item($field, $item, $html = TRUE) {
462      $output = theme('fieldreference_item_simple', $item, $field['multiple']);
463      $output = $html ? check_plain($output) : $output;
464    
465      return $output;
466    }
467    
468    function theme_fieldreference_item_simple($item, $multiple = FALSE) {
469      $output = $item->title . ':' . $item->label;
470    
471      if ($multiple) {
472       $output .= ':' . $item->delta;
473      }
474    
475      return $output;
476    }
477    
478    /**
479     * Provide a list of users to filter on.
480     */
481    function _fieldreference_filter_handler($op, $filterinfo) {
482      $options = array(0 => t('<empty>'));
483      $options = $options + _fieldreference_potential_references($filterinfo['extra']['field']);
484      return $options;
485    }
486    

Legend:
Removed from v.1.2.2.1  
changed lines
  Added in v.1.2.2.2

  ViewVC Help
Powered by ViewVC 1.1.2