- #244896 by stella, canaryMason - Add incremental classes for multiple value fields...
[project/cck.git] / includes / views / content.views.inc
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * Interface between content.module and views.module.
7 */
8
9 // Include the files defining the classes we extend.
10 // This is needed in case the /cck folder lives in the main
11 // /modules folder (views_module_include() will then load
12 // content.views.inc before node.views.inc)
13 module_load_include('inc', 'views', 'modules/node.views');
14
15 /**
16 * Implementation of hook_views_handlers().
17 */
18 function content_views_handlers() {
19 return array(
20 'info' => array(
21 'path' => drupal_get_path('module', 'content') . '/includes/views/handlers',
22 ),
23 'handlers' => array(
24
25 // argument handlers
26 'content_handler_argument' => array(
27 'parent' => 'views_handler_argument',
28 ),
29 'content_handler_argument_string' => array(
30 'parent' => 'views_handler_argument_string',
31 ),
32 'content_handler_argument_numeric' => array(
33 'parent' => 'views_handler_argument_numeric',
34 ),
35 'content_handler_argument_reference' => array(
36 'parent' => 'content_handler_argument_numeric',
37 ),
38 'content_handler_argument_many_to_one' => array(
39 'parent' => 'views_handler_argument_many_to_one',
40 ),
41
42 // field handlers
43 'content_handler_field' => array(
44 'parent' => 'views_handler_field_node',
45 ),
46 'content_handler_field_multiple' => array(
47 'parent' => 'content_handler_field',
48 ),
49
50 // filter handlers
51 'content_handler_filter_string' => array(
52 'parent' => 'views_handler_filter_string',
53 ),
54 'content_handler_filter_numeric' => array(
55 'parent' => 'views_handler_filter_numeric',
56 ),
57 'content_handler_filter_float' => array(
58 'parent' => 'views_handler_filter_float',
59 ),
60 'content_handler_filter_many_to_one' => array(
61 'parent' => 'views_handler_filter_many_to_one',
62 ),
63
64 // relationship handlers
65 'content_handler_relationship' => array(
66 'parent' => 'views_handler_relationship',
67 ),
68
69 // sort handlers
70 'content_handler_sort' => array(
71 'parent' => 'views_handler_sort',
72 ),
73 ),
74 );
75 }
76
77 /**
78 * Implementation of hook_views_plugins.
79 *
80 * Defines some plugins used by the Views modes for
81 * nodereference and userreference.
82 */
83 function content_views_plugins() {
84 $plugins = array(
85 'module' => 'content', // This just tells our themes are elsewhere.
86 'display' => array(
87 'content_simple' => array(
88 'path' => drupal_get_path('module', 'content') . '/includes/views/handlers',
89 // Those strings are not translated for now.
90 // We'll need to change that if / when we remove 'no ui'
91 'title' => 'Simple', // TODO: better name ? (currently not displayed anyway)
92 'help' => 'Destination-agnostic display. Mostly useful for programmatic views.',
93 'handler' => 'content_plugin_display_simple',
94 'no ui' => TRUE, // Programmatic use only.
95 'uses hook menu' => FALSE,
96 'use ajax' => FALSE,
97 'use pager' => FALSE,
98 'accept attachments' => FALSE,
99 ),
100 'content_references' => array(
101 'path' => drupal_get_path('module', 'content') . '/includes/views/handlers',
102 // Those strings are not translated for now.
103 // We'll need to change that if / when we remove 'no ui'
104 'title' => 'Simple - for reference fields', // TODO: better name ? (currently not displayed anyway)
105 'help' => 'Destination-agnostic display. Mostly useful for programmatic views.',
106 'parent' => 'content_simple',
107 'handler' => 'content_plugin_display_references',
108 'no ui' => TRUE, // Programmatic use only.
109 'uses hook menu' => FALSE,
110 'use ajax' => FALSE,
111 'use pager' => FALSE,
112 'accept attachments' => FALSE,
113 ),
114 ),
115 'style' => array(
116 'content_php_array_autocomplete' => array(
117 'path' => drupal_get_path('module', 'content') . '/includes/views/handlers',
118 // Those strings are not translated for now.
119 // We'll need to change that if / when we remove 'no ui'
120 'title' => 'Results array (with title)',
121 'help' => 'Returns the view as a PHP array of names + rendered rows.',
122 'handler' => 'content_plugin_style_php_array_ac',
123 'no ui' => TRUE, // Programmatic use only.
124 'uses row plugin' => TRUE,
125 'uses fields' => TRUE,
126 'type' => 'content_simple',
127 'even empty' => TRUE,
128 ),
129 ),
130 );
131 return $plugins;
132 }
133
134 /**
135 * Implementation of hook_views_data().
136 *
137 * Exposes all fields to the views system.
138 */
139 function content_views_data() {
140 $data = array();
141 foreach (content_fields() as $field) {
142 $module = $field['module'];
143 $result = (array) module_invoke($module, 'field_settings', 'views data', $field);
144 drupal_alter('field_settings', $result, 'views data', $field);
145 if (empty($result)) {
146 $result = content_views_field_views_data($field);
147 }
148 if (is_array($result)) {
149 $data = array_merge($data, $result);
150 }
151 }
152 return $data;
153 }
154
155
156 function content_views_field_views_data($field) {
157 $field_types = _content_field_types();
158
159 // Check the field module is available.
160 // TODO: is this really how we should do it ?
161 if (isset($field_types[$field['type']])) {
162 $db_info = content_database_info($field);
163
164 // Field modules that do not store data in the database
165 // should not create views data tables.
166 if (empty($db_info['columns'])) {
167 return;
168 }
169
170 $table_alias = content_views_tablename($field);
171
172 $types = array();
173 foreach (content_types() as $type) {
174 if (isset($type['fields'][$field['field_name']])) {
175 // TODO : run check_plain here instead of on the imploded string below ?
176 $types[] = $type['name'];
177 }
178 }
179
180 $data = array();
181 $data['table']['group'] = t('Content');
182 $data['table']['join']['node'] = array(
183 'table' => $db_info['table'],
184 'left_field' => 'vid',
185 'field' => 'vid',
186 );
187 $data['table']['join']['node_revisions'] = array(
188 'table' => $db_info['table'],
189 'left_field' => 'vid',
190 'field' => 'vid',
191 );
192
193 // Build the list of columns enabled for default views integration.
194 $db_columns = array();
195 $additional_fields = array();
196 foreach ($db_info['columns'] as $column => $attributes) {
197 // Select explicitly enabled field columns.
198 if (!empty($attributes['views'])) {
199 $db_columns[$column] = $attributes;
200 }
201 // Ensure all columns are retrieved.
202 $additional_fields[$attributes['column']] = $attributes['column'];
203 }
204 // Pick up the first column when none has been explicitly enabled
205 // (pre CCK 2.2 backwards compatibility).
206 if (empty($db_columns)) {
207 // Can't use array_slice(), it won't work in PHP4 for assoc array.
208 foreach ($db_info['columns'] as $column => $attributes) {
209 $db_columns[$column] = $attributes;
210 break;
211 }
212 }
213 $columns = array();
214 $db_fields = array();
215 $arguments = array();
216 $filters = array();
217 foreach ($db_columns as $column => $attributes) {
218 $columns[] = $column;
219 $db_fields[] = $attributes['column'];
220 $sorts[] = !empty($attributes['sortable']) ? TRUE : FALSE;
221
222 // Identify likely filters and arguments for each column based on field type.
223 switch ($attributes['type']) {
224 case 'int':
225 case 'mediumint':
226 case 'tinyint':
227 case 'bigint':
228 case 'serial':
229 $filters[] = 'content_handler_filter_numeric';
230 $arguments[] = 'content_handler_argument_numeric';
231 break;
232 case 'numeric':
233 case 'float':
234 $filters[] = 'content_handler_filter_float';
235 $arguments[] = 'content_handler_argument_numeric';
236 break;
237
238 case 'text':
239 case 'blob':
240 // TODO add markup handlers for these types
241 default:
242 $filters[] = 'content_handler_filter_string';
243 $arguments[] = 'content_handler_argument_string';
244 break;
245 }
246 }
247
248 // Provide automatic filters, sorts, and arguments for each column, not just the first.
249 $db_fields_count = count($db_fields);
250 foreach ($db_fields as $i => $db_field) {
251 $label_truncated = truncate_utf8(t($field['widget']['label']), 10, TRUE);
252 if ($db_fields_count == 1) {
253 $title = t('@label (!name)', array('@label' => t($field['widget']['label']), '!name' => $field['field_name']));
254 $title_short = check_plain($label_truncated);
255 }
256 else {
257 $title = t('@label (!name) - !column', array('@label' => t($field['widget']['label']), '!name' => $field['field_name'], '!column' => $columns[$i]));
258 $title_short = t('@label-truncated - !column', array('@label-truncated' => $label_truncated, '!column' => $columns[$i]));
259 }
260
261 $data[$db_field] = array(
262 'group' => t('Content'),
263 'title' => $title,
264 'title short' => $title_short,
265 'help' => t($field_types[$field['type']]['label']) .' - '. t('Appears in: @types', array('@types' => implode(', ', $types))),
266 );
267 if ($i == 0) {
268 $data[$db_field]['field'] = array(
269 'title' => t('@label (!name)', array('@label' => t($field['widget']['label']), '!name' => $field['field_name'])),
270 'title short' => check_plain($label_truncated),
271 'field' => $db_field,
272 'table' => $db_info['table'],
273 'handler' => 'content_handler_field_multiple',
274 'click sortable' => $sorts[$i],
275 'additional fields' => $additional_fields,
276 'content_field_name' => $field['field_name'],
277 'access callback' => 'content_access',
278 'access arguments' => array('view', $field),
279 );
280 }
281 $data[$db_field]['argument'] = array(
282 'field' => $db_field,
283 'table' => $db_info['table'],
284 'handler' => $arguments[$i],
285 'additional fields' => $additional_fields,
286 'content_field_name' => $field['field_name'],
287 'empty field name' => t('<No value>'),
288 );
289 $data[$db_field]['filter'] = array(
290 'field' => $db_field,
291 'table' => $db_info['table'],
292 'handler' => $filters[$i],
293 'additional fields' => $additional_fields,
294 'content_field_name' => $field['field_name'],
295 'allow empty' => TRUE,
296 );
297 if (!empty($sorts[$i])) {
298 $data[$db_field]['sort'] = array(
299 'field' => $db_field,
300 'table' => $db_info['table'],
301 'handler' => 'content_handler_sort',
302 'additional fields' => $additional_fields,
303 'content_field_name' => $field['field_name'],
304 );
305 }
306 }
307 return array($table_alias => $data);
308 }
309 }
310
311 /**
312 * Helper function so it is possible to change the Views tablename
313 * in the future without re-writing code.
314 */
315 function content_views_tablename($field) {
316 return 'node_data_'. $field['field_name'];
317 }
318
319 function theme_content_view_multiple_field($items, $field, $values) {
320 $output = '';
321 $i = 0;
322 foreach ($items as $item) {
323 if (!empty($item) || $item == '0') {
324 $output .= '<div class="field-item field-item-'. $i .'">'. $item .'</div>';
325 $i++;
326 }
327 }
328 return $output;
329 }