• Main Page
  • Related Pages
  • Modules
  • Classes
  • Files
  • File List
  • File Members

plugins/views_plugin_style.inc

00001 <?php
00002 
00020 class views_plugin_style extends views_plugin {
00024   var $row_tokens = array();
00034   function init(&$view, &$display, $options = NULL) {
00035     $this->view = &$view;
00036     $this->display = &$display;
00037 
00038     // Overlay incoming options on top of defaults
00039     $this->unpack_options($this->options, isset($options) ? $options : $display->handler->get_option('style_options'));
00040 
00041     if ($this->uses_row_plugin() && $display->handler->get_option('row_plugin')) {
00042       $this->row_plugin = $display->handler->get_plugin('row');
00043     }
00044 
00045     $this->options += array(
00046       'grouping' => array(),
00047     );
00048 
00049     $this->definition += array(
00050       'uses grouping' => TRUE,
00051     );
00052   }
00053 
00054   function destroy() {
00055     parent::destroy();
00056 
00057     if (isset($this->row_plugin)) {
00058       $this->row_plugin->destroy();
00059     }
00060   }
00061 
00065   function uses_row_plugin() {
00066     return !empty($this->definition['uses row plugin']);
00067   }
00068 
00072   function uses_row_class() {
00073     return !empty($this->definition['uses row class']);
00074   }
00075 
00079   function uses_fields() {
00080     // If we use a row plugin, ask the row plugin. Chances are, we don't
00081     // care, it does.
00082     if ($this->uses_row_plugin() && !empty($this->row_plugin)) {
00083       return $this->row_plugin->uses_fields();
00084     }
00085     // Otherwise, maybe we do.
00086     return !empty($this->definition['uses fields']);
00087   }
00088 
00094   function uses_tokens() {
00095     if ($this->uses_row_class()) {
00096       $class = $this->options['row_class'];
00097       if (strpos($class, '[') !== FALSE || strpos($class, '!') !== FALSE || strpos($class, '%') !== FALSE) {
00098         return TRUE;
00099       }
00100     }
00101   }
00102 
00106   function get_row_class($row_index) {
00107     if ($this->uses_row_class()) {
00108       $class = $this->options['row_class'];
00109       if ($this->uses_fields() && $this->view->field) {
00110         $class = strip_tags($this->tokenize_value($class, $row_index));
00111       }
00112 
00113       $classes = explode(' ', $class);
00114       foreach ($classes as &$class) {
00115         $class = drupal_clean_css_identifier($class);
00116       }
00117       return implode(' ', $classes);
00118     }
00119   }
00120 
00124   function tokenize_value($value, $row_index) {
00125     if (strpos($value, '[') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) {
00126       $fake_item = array(
00127         'alter_text' => TRUE,
00128         'text' => $value,
00129       );
00130 
00131       // Row tokens might be empty, for example for node row style.
00132       $tokens = isset($this->row_tokens[$row_index]) ? $this->row_tokens[$row_index] : array();
00133       if (!empty($this->view->build_info['substitutions'])) {
00134         $tokens += $this->view->build_info['substitutions'];
00135       }
00136 
00137       if ($tokens) {
00138         $value = strtr($value, $tokens);
00139       }
00140     }
00141 
00142     return $value;
00143   }
00144 
00148   function even_empty() {
00149     return !empty($this->definition['even empty']);
00150   }
00151 
00152   function option_definition() {
00153     $options = parent::option_definition();
00154     $options['grouping'] = array('default' => array());
00155     if ($this->uses_row_class()) {
00156       $options['row_class'] = array('default' => '');
00157     }
00158 
00159     return $options;
00160   }
00161 
00162   function options_form(&$form, &$form_state) {
00163     parent::options_form($form, $form_state);
00164     // Only fields-based views can handle grouping.  Style plugins can also exclude
00165     // themselves from being groupable by setting their "use grouping" definiton
00166     // key to FALSE.
00167     // @TODO: Document "uses grouping" in docs.php when docs.php is written.
00168     if ($this->uses_fields() && $this->definition['uses grouping']) {
00169       $options = array('' => t('- None -'));
00170       $field_labels = $this->display->handler->get_field_labels();
00171       $options += $field_labels;
00172 
00173       // If there are no fields, we can't group on them.
00174       if (count($options) > 1) {
00175         // This is for backward compability, when there was just a single select form.
00176         if (is_string($this->options['grouping'])) {
00177           $grouping = $this->options['grouping'];
00178           $this->options['grouping'] = array();
00179           $this->options['grouping'][0]['field'] = $grouping;
00180         }
00181         if (isset($this->options['group_rendered']) && is_string($this->options['group_rendered'])) {
00182           $this->options['grouping'][0]['rendered'] = $this->options['group_rendered'];
00183           unset($this->options['group_rendered']);
00184         }
00185 
00186         $c = count($this->options['grouping']);
00187         // Add a form for every grouping, plus one.
00188         for ($i = 0; $i <= $c; $i++) {
00189           $grouping = !empty($this->options['grouping'][$i]) ? $this->options['grouping'][$i] : array();
00190           $grouping += array('field' => '', 'rendered' => TRUE, 'rendered_strip' => FALSE);
00191           $form['grouping'][$i]['field'] = array(
00192             '#type' => 'select',
00193             '#title' => t('Grouping field Nr.@number', array('@number' => $i + 1)),
00194             '#options' => $options,
00195             '#default_value' => $grouping['field'],
00196             '#description' => t('You may optionally specify a field by which to group the records. Leave blank to not group.'),
00197           );
00198           $form['grouping'][$i]['rendered'] = array(
00199             '#type' => 'checkbox',
00200             '#title' => t('Use rendered output to group rows'),
00201             '#default_value' => $grouping['rendered'],
00202             '#description' => t('If enabled the rendered output of the grouping field is used to group the rows.'),
00203             '#dependency' => array(
00204               'edit-style-options-grouping-' . $i . '-field' => array_keys($field_labels),
00205             )
00206           );
00207           $form['grouping'][$i]['rendered_strip'] = array(
00208             '#type' => 'checkbox',
00209             '#title' => t('Remove tags from rendered output'),
00210             '#default_value' => $grouping['rendered_strip'],
00211             '#dependency' => array(
00212               'edit-style-options-grouping-' . $i . '-field' => array_keys($field_labels),
00213             )
00214           );
00215         }
00216       }
00217     }
00218 
00219     if ($this->uses_row_class()) {
00220       $form['row_class'] = array(
00221         '#title' => t('Row class'),
00222         '#description' => t('The class to provide on each row.'),
00223         '#type' => 'textfield',
00224         '#default_value' => $this->options['row_class'],
00225       );
00226 
00227       if ($this->uses_fields()) {
00228         $form['row_class']['#description'] .= ' ' . t('You may use field tokens from as per the "Replacement patterns" used in "Rewrite the output of this field" for all fields.');
00229       }
00230     }
00231   }
00232 
00233   function options_validate(&$form, &$form_state) {
00234     // Don't run validation on style plugins without the grouping setting.
00235     if (isset($form_state['values']['style_options']['grouping'])) {
00236       // Don't save grouping if no field is specified.
00237       foreach ($form_state['values']['style_options']['grouping'] as $index => $grouping) {
00238         if (empty($grouping['field'])) {
00239           unset($form_state['values']['style_options']['grouping'][$index]);
00240         }
00241       }
00242     }
00243   }
00244 
00250   function build_sort() { return TRUE; }
00251 
00256   function build_sort_post() { }
00257 
00264   function pre_render($result) {
00265     if (!empty($this->row_plugin)) {
00266       $this->row_plugin->pre_render($result);
00267     }
00268   }
00269 
00273   function render() {
00274     if ($this->uses_row_plugin() && empty($this->row_plugin)) {
00275       debug('views_plugin_style_default: Missing row plugin');
00276       return;
00277     }
00278 
00279     // Group the rows according to the grouping instructions, if specified.
00280     $sets = $this->render_grouping(
00281       $this->view->result,
00282       $this->options['grouping'],
00283       TRUE
00284     );
00285 
00286     return $this->render_grouping_sets($sets);
00287   }
00288 
00303   function render_grouping_sets($sets, $level = 0) {
00304     $output = '';
00305     foreach ($sets as $set) {
00306       $row = reset($set['rows']);
00307       // Render as a grouping set.
00308       if (is_array($row) && isset($row['group'])) {
00309         $output .= theme(views_theme_functions('views_view_grouping', $this->view, $this->display),
00310           array(
00311             'view' => $this->view,
00312             'grouping' => $this->options['grouping'][$level],
00313             'grouping_level' => $level,
00314             'rows' => $set['rows'],
00315             'title' => $set['group'])
00316         );
00317       }
00318       // Render as a record set.
00319       else {
00320         if ($this->uses_row_plugin()) {
00321           foreach ($set['rows'] as $index => $row) {
00322             $this->view->row_index = $index;
00323             $set['rows'][$index] = $this->row_plugin->render($row);
00324           }
00325         }
00326 
00327         $output .= theme($this->theme_functions(),
00328           array(
00329             'view' => $this->view,
00330             'options' => $this->options,
00331             'grouping_level' => $level,
00332             'rows' => $set['rows'],
00333             'title' => $set['group'])
00334         );
00335       }
00336     }
00337     unset($this->view->row_index);
00338     return $output;
00339   }
00340 
00380   function render_grouping($records, $groupings = array(), $group_rendered = NULL) {
00381     // This is for backward compability, when $groupings was a string containing
00382     // the ID of a single field.
00383     if (is_string($groupings)) {
00384       $rendered = $group_rendered === NULL ? TRUE : $group_rendered;
00385       $groupings = array(array('field' => $groupings, 'rendered' => $rendered));
00386     }
00387 
00388     // Make sure fields are rendered
00389     $this->render_fields($this->view->result);
00390     $sets = array();
00391     if ($groupings) {
00392       foreach ($records as $index => $row) {
00393         // Iterate through configured grouping fields to determine the
00394         // hierarchically positioned set where the current row belongs to.
00395         // While iterating, parent groups, that do not exist yet, are added.
00396         $set = &$sets;
00397         foreach ($groupings as $info) {
00398           $field = $info['field'];
00399           $rendered = isset($info['rendered']) ? $info['rendered'] : $group_rendered;
00400           $rendered_strip = isset($info['rendered_strip']) ? $info['rendered_strip'] : FALSE;
00401           $grouping = '';
00402           $group_content = '';
00403           // Group on the rendered version of the field, not the raw.  That way,
00404           // we can control any special formatting of the grouping field through
00405           // the admin or theme layer or anywhere else we'd like.
00406           if (isset($this->view->field[$field])) {
00407             $group_content = $this->get_field($index, $field);
00408             if ($this->view->field[$field]->options['label']) {
00409               $group_content = $this->view->field[$field]->options['label'] . ': ' . $group_content;
00410             }
00411             if ($rendered) {
00412               $grouping = $group_content;
00413               if ($rendered_strip) {
00414                 $group_content = $grouping = strip_tags(htmlspecialchars_decode($group_content));
00415               }
00416             }
00417             else {
00418               $grouping = $this->get_field_value($index, $field);
00419               // Not all field handlers return a scalar value,
00420               // e.g. views_handler_field_field.
00421               if (!is_scalar($grouping)) {
00422                 $grouping = md5(serialize($grouping));
00423               }
00424             }
00425           }
00426 
00427           // Create the group if it does not exist yet.
00428           if (empty($set[$grouping])) {
00429             $set[$grouping]['group'] = $group_content;
00430             $set[$grouping]['rows'] = array();
00431           }
00432 
00433           // Move the set reference into the row set of the group we just determined.
00434           $set = &$set[$grouping]['rows'];
00435         }
00436         // Add the row to the hierarchically positioned row set we just determined.
00437         $set[$index] = $row;
00438       }
00439     }
00440     else {
00441       // Create a single group with an empty grouping field.
00442       $sets[''] = array(
00443         'group' => '',
00444         'rows' => $records,
00445       );
00446     }
00447 
00448     // If this parameter isn't explicitely set modify the output to be fully
00449     // backward compatible to code before Views 7.x-3.0-rc2.
00450     // @TODO Remove this as soon as possible e.g. October 2020
00451     if ($group_rendered === NULL) {
00452       $old_style_sets = array();
00453       foreach ($sets as $group) {
00454         $old_style_sets[$group['group']] = $group['rows'];
00455       }
00456       $sets = $old_style_sets;
00457     }
00458 
00459     return $sets;
00460   }
00461 
00468   function render_fields($result) {
00469     if (!$this->uses_fields()) {
00470       return;
00471     }
00472 
00473     if (!isset($this->rendered_fields)) {
00474       $this->rendered_fields = array();
00475       $this->view->row_index = 0;
00476       $keys = array_keys($this->view->field);
00477 
00478       // If all fields have a field::access FALSE there might be no fields, so
00479       // there is no reason to execute this code.
00480       if (!empty($keys)) {
00481         foreach ($result as $count => $row) {
00482           $this->view->row_index = $count;
00483           foreach ($keys as $id) {
00484             $this->rendered_fields[$count][$id] = $this->view->field[$id]->theme($row);
00485           }
00486 
00487           $this->row_tokens[$count] = $this->view->field[$id]->get_render_tokens(array());
00488         }
00489       }
00490       unset($this->view->row_index);
00491     }
00492 
00493     return $this->rendered_fields;
00494   }
00495 
00504   function get_field($index, $field) {
00505     if (!isset($this->rendered_fields)) {
00506       $this->render_fields($this->view->result);
00507     }
00508 
00509     if (isset($this->rendered_fields[$index][$field])) {
00510       return $this->rendered_fields[$index][$field];
00511     }
00512   }
00513 
00522   function get_field_value($index, $field) {
00523     $this->view->row_index = $index;
00524     $value = $this->view->field[$field]->get_value($this->view->result[$index]);
00525     unset($this->view->row_index);
00526     return $value;
00527   }
00528 
00529   function validate() {
00530     $errors = parent::validate();
00531 
00532     if ($this->uses_row_plugin()) {
00533       $plugin = $this->display->handler->get_plugin('row');
00534       if (empty($plugin)) {
00535         $errors[] = t('Style @style requires a row style but the row plugin is invalid.', array('@style' => $this->definition['title']));
00536       }
00537       else {
00538         $result = $plugin->validate();
00539         if (!empty($result) && is_array($result)) {
00540           $errors = array_merge($errors, $result);
00541         }
00542       }
00543     }
00544     return $errors;
00545   }
00546 
00547   function query() {
00548     parent::query();
00549     if (isset($this->row_plugin)) {
00550       $this->row_plugin->query();
00551     }
00552   }
00553 }
00554 

Generated on Sun Feb 26 2012 12:52:52 for Views by  doxygen 1.7.1