| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: content_handler_field_multiple.inc,v 1.1.2.26 2011/01/07 13:33:55 yched Exp $ 3 4 /** 5 * @file 6 * An extended subclass for field handling that adds multiple field grouping. 7 * 8 * Fields that want multiple value grouping options in addition to basic 9 * field and formatter handling can extend this class. 10 */ 11 class content_handler_field_multiple extends content_handler_field { 12 var $defer_query; 13 14 function init(&$view, $options) { 15 $field = $this->content_field; 16 parent::init($view, $options); 17 18 $this->defer_query = !empty($options['multiple']['group']) && $field['multiple']; 19 20 if ($this->defer_query) { 21 // Grouped field: ditch the existing additional_fields (field columns + delta). 22 // In the main query we'll only need: 23 // - vid, which will be used to retrieve the actual values in pre_render, 24 // - node type and nid, which wil be used in the pseudo-node used when 25 // rendering. 26 $this->additional_fields = array( 27 'type' => array('table' => 'node', 'field' => 'type'), 28 'nid' => array('table' => 'node', 'field' => 'nid'), 29 ); 30 if ($view->base_table == 'node_revisions') { 31 $this->additional_fields['vid'] = array('table' => 'node_revisions', 'field' => 'vid'); 32 } 33 else { 34 $this->additional_fields['vid'] = array('table' => 'node', 'field' => 'vid'); 35 } 36 } 37 } 38 39 function option_definition() { 40 $options = parent::option_definition(); 41 42 $options['multiple'] = array( 43 'contains' => array( 44 'group' => array('default' => TRUE), 45 'multiple_number' => array('default' => ''), 46 'multiple_from' => array('default' => ''), 47 'multiple_reversed' => array('default' => FALSE), 48 ), 49 ); 50 51 return $options; 52 } 53 54 /** 55 * Provide 'group multiple values' option. 56 */ 57 function options_form(&$form, &$form_state) { 58 parent::options_form($form, $form_state); 59 60 $field = $this->content_field; 61 $options = $this->options; 62 63 $form['multiple'] = array( 64 '#access' => $field['multiple'], 65 '#weight' => 1, 66 ); 67 $form['multiple']['group'] = array( 68 '#title' => t('Group multiple values'), 69 '#type' => 'checkbox', 70 '#default_value' => $options['multiple']['group'], 71 '#description' => t('If unchecked, each item in the field will create a new row, which may appear to cause duplicates. This setting is not compatible with click-sorting in table displays.'), 72 ); 73 // Make the string translatable by keeping it as a whole rather than 74 // translating prefix and suffix separately. 75 list($prefix, $suffix) = explode('@count', t('Show @count value(s)')); 76 $form['multiple']['multiple_number'] = array( 77 '#type' => 'textfield', 78 '#size' => 5, 79 '#field_prefix' => $prefix, 80 '#field_suffix' => $suffix, 81 '#default_value' => $options['multiple']['multiple_number'], 82 '#prefix' => '<div class="container-inline">', 83 '#process' => array('views_process_dependency'), 84 '#dependency' => array('edit-options-multiple-group' => array(TRUE)), 85 ); 86 list($prefix, $suffix) = explode('@count', t('starting from @count')); 87 $form['multiple']['multiple_from'] = array( 88 '#type' => 'textfield', 89 '#size' => 5, 90 '#field_prefix' => $prefix, 91 '#field_suffix' => $suffix, 92 '#default_value' => $options['multiple']['multiple_from'], 93 '#process' => array('views_process_dependency'), 94 '#dependency' => array('edit-options-multiple-group' => array(TRUE)), 95 '#description' => t('(first item is 0)'), 96 ); 97 $form['multiple']['multiple_reversed'] = array( 98 '#title' => t('Reversed'), 99 '#type' => 'checkbox', 100 '#default_value' => $options['multiple']['multiple_reversed'], 101 '#suffix' => '</div>', 102 '#process' => array('views_process_dependency'), 103 '#dependency' => array('edit-options-multiple-group' => array(TRUE)), 104 '#description' => t('(start from last values)'), 105 ); 106 } 107 108 /** 109 * Determine if this field is click sortable. 110 */ 111 function click_sortable() { 112 $field = $this->content_field; 113 $options = $this->options; 114 115 // Grouped fields are not click-sortable. 116 return !empty($this->definition['click sortable']) && !$this->defer_query; 117 } 118 119 function query() { 120 // If this is not a grouped field, use the generic query(). 121 if (!$this->defer_query) { 122 return parent::query(); 123 } 124 125 // Grouped field: do NOT call ensure_my_table, only add additional fields. 126 $this->add_additional_fields(); 127 $this->field_alias = $this->aliases['vid']; 128 } 129 130 function pre_render($values) { 131 // If there are no values to render (displaying a summary, or query returned no results), 132 // or if this is not a grouped field, do nothing specific. 133 if (isset($this->view->build_info['summary']) || empty($values) || !$this->defer_query) { 134 return parent::pre_render($values); 135 } 136 137 $field = $this->content_field; 138 $db_info = content_database_info($field); 139 $options = $this->options; 140 141 // Build the list of vids to retrieve. 142 // TODO: try fetching from cache_content first ?? 143 $vids = array(); 144 $this->field_values = array(); 145 foreach ($values as $result) { 146 if (isset($result->{$this->field_alias})) { 147 $vids[] = $result->{$this->field_alias}; 148 } 149 } 150 151 // It may happend that the multiple values field is related to a non 152 // required relation for which no node data related to the field being 153 // processed here is available. 154 if (empty($vids)) { 155 return parent::pre_render($values); 156 } 157 158 // List columns to retrieve. 159 $alias = content_views_tablename($field); 160 // Prefix aliases with '_' to avoid clashing with field columns names. 161 $query_columns = array( 162 'vid AS _vid', 163 "delta as _delta", 164 // nid is needed to generate the links for 'link to node' option. 165 'nid AS _nid', 166 ); 167 // The actual field columns. 168 foreach ($db_info['columns'] as $column => $attributes) { 169 $query_columns[] = "$attributes[column] AS $column"; 170 } 171 $query = 'SELECT '. implode(', ', $query_columns) . 172 ' FROM {'. $db_info['table'] ."}". 173 " WHERE vid IN (". implode(',', $vids) .')'. 174 " ORDER BY _nid ASC, _delta ". ($options['multiple']['multiple_reversed'] ? 'DESC' : 'ASC'); 175 $result = db_query($query); 176 177 while ($item = db_fetch_array($result)) { 178 // Clean up the $item from vid and delta. We keep nid for now. 179 $vid = $item['_vid']; 180 unset($item['_vid']); 181 $delta = !empty($item['_delta']) ? $item['_delta'] : 0; 182 $item['#delta'] = $item['_delta']; 183 unset($item['_delta']); 184 $this->field_values[$vid][$delta] = $item; 185 } 186 } 187 188 /** 189 * Return DIV or SPAN based upon the field's element type. 190 * 191 * Fields rendered with the 'group multiple' option use <div> markers, 192 * and thus shouldn't be wrapped in a <span>. 193 */ 194 function element_type($none_supported = FALSE, $default_empty = FALSE) { 195 // If this is not a grouped field, use the parent method. 196 if (!$this->defer_query) { 197 return parent::element_type($none_supported, $default_empty); 198 } 199 200 // The 'element_type' property denotes Views 3.x ('semantic views' 201 // functionnality). If the property is set, and not set to '' ("default"), 202 // let the generic method handle the output. 203 if (isset($this->options['element_type']) && $this->options['element_type'] !== '') { 204 return parent::element_type($none_supported, $default_empty); 205 } 206 207 if ($default_empty) { 208 return ''; 209 } 210 211 if (isset($this->definition['element type'])) { 212 return $this->definition['element type']; 213 } 214 215 return 'div'; 216 } 217 218 function render($values) { 219 // If this is not a grouped field, use content_handler_field::render(). 220 if (!$this->defer_query) { 221 return parent::render($values); 222 } 223 224 // We're down to a single node here, so we can retrieve the actual field 225 // definition for the node type being considered. 226 $field = content_fields($this->content_field['field_name'], $values->{$this->aliases['type']}); 227 228 // If the field does not appear in the node type, then we have no value 229 // to display, and can just return. 230 if (empty($field)) { 231 return ''; 232 } 233 234 $options = $this->options; 235 236 $vid = $values->{$this->field_alias}; 237 if (isset($this->field_values[$vid])) { 238 // Gather items, respecting the 'Display n values starting from m' settings. 239 $count_skipped = 0; 240 $items = array(); 241 foreach ($this->field_values[$vid] as $item) { 242 if (empty($options['multiple']['multiple_from']) || ($count_skipped >= $options['multiple']['multiple_from'])) { 243 if (empty($options['multiple']['multiple_number']) || (count($items) < $options['multiple']['multiple_number'])) { 244 // Grab the nid - needed for render_link(). 245 $nid = $item['_nid']; 246 unset($item['_nid']); 247 $items[] = $item; 248 } 249 else { 250 break; 251 } 252 } 253 $count_skipped++; 254 } 255 256 // Build a pseudo-node from the retrieved values. 257 $node = drupal_clone($values); 258 // content_format and formatters will need a 'type'. 259 $node->type = $values->{$this->aliases['type']}; 260 $node->nid = $values->{$this->aliases['nid']}; 261 $node->vid = $values->{$this->aliases['vid']}; 262 263 // Some formatters need to behave differently depending on the build_mode 264 // (for instance: preview), so we provide one. 265 $node->build_mode = NODE_BUILD_NORMAL; 266 267 // Render items. 268 $formatter_name = $options['format']; 269 if ($items && ($formatter = _content_get_formatter($formatter_name, $field['type']))) { 270 $rendered = array(); 271 if (content_handle('formatter', 'multiple values', $formatter) == CONTENT_HANDLE_CORE) { 272 // Single-value formatter. 273 foreach ($items as $item) { 274 $output = content_format($field, $item, $formatter_name, $node); 275 if (!empty($output)) { 276 $rendered[] = $this->render_link($output, (object) array('nid' => $nid)); 277 } 278 } 279 } 280 else { 281 // Multiple values formatter. 282 $output = content_format($field, $items, $formatter_name, $values); 283 if (!empty($output)) { 284 $rendered[] = $this->render_link($output, (object) array('nid' => $nid)); 285 } 286 } 287 288 if (count($rendered) > 1) { 289 // TODO: could we use generic field display ? 290 return theme('content_view_multiple_field', $rendered, $field, $values); 291 } 292 elseif ($rendered) { 293 return $rendered[0]; 294 } 295 } 296 } 297 298 return ''; 299 } 300 301 function render_link($data, $values) { 302 if (!$this->defer_query) { 303 return parent::render_link($data, $values); 304 } 305 306 if (!empty($this->options['link_to_node']) && $data !== NULL && $data !== '') { 307 if (method_exists('render_as_link', 'views_handler_field')) { 308 // Views 2.3+ 309 $this->options['alter']['make_link'] = TRUE; 310 $this->options['alter']['path'] = "node/" . $values->{$this->aliases['nid']}; 311 } 312 else { 313 // Views up to 2.2 314 return l($data, "node/" . $values->nid, array('html' => TRUE)); 315 } 316 } 317 else { 318 return $data; 319 } 320 } 321 322 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |