5 * @defgroup views_style_plugins Views' style plugins
7 * Style plugins control how a view is rendered. For example, they
8 * can choose to display a collection of fields, node_view() output,
9 * table output, or any kind of crazy output they want.
11 * Many style plugins can have an optional 'row' plugin, that displays
12 * a single record. Not all style plugins can utilize this, so it is
13 * up to the plugin to set this up and call through to the row plugin.
15 * @see hook_views_plugins
19 * Base class to define a style plugin handler.
21 class views_plugin_style
extends views_plugin
{
23 * Initialize a style plugin.
28 * The style options might come externally as the style can be sourced
29 * from at least two locations. If it's not included, look on the display.
31 function init(&$view, &$display, $options = NULL
) {
33 $this->display
= &$display;
35 // Overlay incoming options on top of defaults
36 $this->unpack_options($this->options
, isset($options) ?
$options : $display->handler
->get_option('style_options'));
38 if ($this->uses_row_plugin() && $display->handler
->get_option('row_plugin')) {
39 $this->row_plugin
= $display->handler
->get_plugin('row');
42 $this->options
+= array(
46 $this->definition
+= array(
47 'uses grouping' => TRUE
,
54 if (isset($this->row_plugin
)) {
55 $this->row_plugin
->destroy();
60 * Return TRUE if this style also uses a row plugin.
62 function uses_row_plugin() {
63 return !empty($this->definition
['uses row plugin']);
67 * Return TRUE if this style also uses fields.
69 function uses_fields() {
70 // If we use a row plugin, ask the row plugin. Chances are, we don't
72 if ($this->uses_row_plugin() && !empty($this->row_plugin
)) {
73 return $this->row_plugin
->uses_fields();
75 // Otherwise, maybe we do.
76 return !empty($this->definition
['uses fields']);
79 function option_definition() {
80 $options = parent
::option_definition();
81 $options['grouping'] = array('default' => '');
85 function options_form(&$form, &$form_state) {
86 // Only fields-based views can handle grouping. Style plugins can also exclude
87 // themselves from being groupable by setting their "use grouping" definiton
89 // @TODO: Document "uses grouping" in docs.php when docs.php is written.
90 if ($this->uses_fields() && $this->definition
['uses grouping']) {
91 $options = array('' => t('<None>'));
92 foreach ($this->display
->handler
->get_handlers('field') as
$field => $handler) {
94 if ($label = $handler->label()) {
95 $options[$field] = $label;
98 $options[$field] = $handler->ui_name();
102 // If there are no fields, we can't group on them.
103 if (count($options) > 1) {
104 $form['grouping'] = array(
106 '#title' => t('Grouping field'),
107 '#options' => $options,
108 '#default_value' => $this->options
['grouping'],
109 '#description' => t('You may optionally specify a field by which to group the records. Leave blank to not group.'),
116 * Called by the view builder to see if this style handler wants to
117 * interfere with the sorts. If so it should build; if it returns
118 * any non-TRUE value, normal sorting will NOT be added to the query.
120 function build_sort() { return TRUE
; }
123 * Called by the view builder to let the style build a second set of
124 * sorts that will come after any other sorts in the view.
126 function build_sort_post() { }
129 * Allow the style to do stuff before each row is rendered.
132 * The full array of results from the query.
134 function pre_render($result) {
135 if (!empty($this->row_plugin
)) {
136 $this->row_plugin
->pre_render($result);
141 * Render the display in this style.
144 if ($this->uses_row_plugin() && empty($this->row_plugin
)) {
145 vpr('views_plugin_style_default: Missing row plugin');
149 // Group the rows according to the grouping field, if specified.
150 $sets = $this->render_grouping($this->view
->result
, $this->options
['grouping']);
152 // Render each group separately and concatenate. Plugins may override this
153 // method if they wish some other way of handling grouping.
155 $this->view
->row_index
= 0;
156 foreach ($sets as
$title => $records) {
157 if ($this->uses_row_plugin()) {
159 foreach ($records as
$label => $row) {
160 $rows[] = $this->row_plugin
->render($row);
161 $this->view
->row_index
++;
168 $output .
= theme($this->theme_functions(), $this->view
, $this->options
, $rows, $title);
170 unset($this->view
->row_index
);
175 * Group records as needed for rendering.
178 * An array of records from the view to group.
179 * @param $grouping_field
180 * The field id on which to group. If empty, the result set will be given
181 * a single group with an empty string as a label.
183 * The grouped record set.
185 function render_grouping($records, $grouping_field = '') {
187 if ($grouping_field) {
188 $this->view
->row_index
= 0;
189 foreach ($records as
$row) {
191 // Group on the rendered version of the field, not the raw. That way,
192 // we can control any special formatting of the grouping field through
193 // the admin or theme layer or anywhere else we'd like.
194 if (isset($this->view
->field
[$grouping_field])) {
195 $grouping = $this->view
->field
[$grouping_field]->theme($row);
196 $this->view
->row_index
++;
197 if ($this->view
->field
[$grouping_field]->options
['label']) {
198 $grouping = $this->view
->field
[$grouping_field]->options
['label'] .
': ' .
$grouping;
201 $sets[$grouping][] = $row;
203 unset($this->view
->row_index
);
206 // Create a single group with an empty grouping field.
207 $sets[''] = $records;
212 function validate() {
213 $errors = parent
::validate();
215 if ($this->uses_row_plugin()) {
216 $plugin = $this->display
->handler
->get_plugin('row');
217 if (empty($plugin)) {
218 $errors[] = t('Style @style requires a row style but the row plugin is invalid.', array('@style' => $this->definition
['title']));
226 if (isset($this->row_plugin
)) {
227 $this->row_plugin
->query();