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

Contents of /contributions/modules/value_provider/value_provider.module

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


Revision 1.4 - (show annotations) (download) (as text)
Fri Jan 16 18:50:11 2009 UTC (10 months, 1 week ago) by jpetso
Branch: MAIN
CVS Tags: DRUPAL-6--1-0-RC1, HEAD
Changes since 1.3: +7 -3 lines
File MIME type: text/x-php
Make Value Providers really independent of CCK, like the .info file suggests.
The current set of providers doesn't provide any other values than CCK ones
so running it without CCK *and* further extensions is kinda pointless,
but external providers can still add providers and don't need CCK for that.
So, away with the hidden dependency.
1 <?php
2 // $Id: value_provider.module,v 1.3 2009/01/16 18:30:24 jpetso Exp $
3 /**
4 * @file
5 * Value Providers - Semantic result values for programmatic Views usage.
6 *
7 * Copyright 2008 by Jakob Petsovits ("jpetso", http://drupal.org/user/56020)
8 */
9
10 include_once(drupal_get_path('module', 'value_provider') . '/value_provider.providers.inc');
11
12 /**
13 * Retrieve a list of value providers, optionally filtered by their value type.
14 *
15 * @param $value_type
16 * If set, only the part of the array containing providers of the given
17 * value type (e.g. 'nid' or 'hours') will be returned. If NULL (default),
18 * the whole structured provider info array will be returned.
19 *
20 * @return
21 * An array in the following format (including some example values):
22 * <code>
23 * array(
24 * 'hours' => array(
25 * 'field_timeneed' => array( // provider name
26 * 'name' => 'field_timeneed', // provider name, too
27 * 'provides' => 'hours', // value type
28 * 'title' => t('Time need field (field_timeneed)'),
29 * 'views table' => $cck_timeneed_views_table_name,
30 * 'columns' => array(
31 * 'iso8601' => $iso8601_real_column_name,
32 * 'seconds' => $seconds_real_column_name,
33 * ),
34 * 'parse callback' => 'mymodule_parse_duration_hours',
35 * 'extra' => $array_with_optional_field_specific_info,
36 * ),
37 * ...
38 * ),
39 * 'nid' => array(
40 * 'field_parent' => array(
41 * 'name' => 'field_parent',
42 * 'provides' => 'nid',
43 * 'title' => t('Parent Node field (field_parent)'),
44 * 'views table' => $cck_timeneed_views_parentnode_name,
45 * 'columns' => array(
46 * 'nid' => $nid_real_column_name,
47 * ),
48 * 'parse callback' => 'mymodule_parse_nodereference_nid',
49 * 'extra' => $array_with_optional_field_specific_info,
50 * ),
51 * ...
52 * ),
53 * ...
54 * )</code>
55 */
56 function value_providers($value_type = NULL) {
57 static $providers_by_type;
58 if (!isset($providers_by_type)) {
59 views_include_handlers();
60 if (module_exists('content')) {
61 module_load_include('inc', 'content', 'includes/content.views');
62 }
63
64 $providers_by_type = module_invoke_all('value_provider_info');
65 drupal_alter('value_provider_info', $providers_by_type);
66
67 // Insert a few default values.
68 foreach ($providers_by_type as $provider_value_type => $value_providers) {
69 foreach ($value_providers as $provider_name => $provider) {
70 $provider['provides'] = $provider_value_type;
71 $provider['name'] = $provider_name;
72 $providers_by_type[$provider_value_type][$provider_name] = $provider;
73 }
74 }
75 }
76 if (isset($value_type)) {
77 return isset($providers_by_type[$value_type])
78 ? $providers_by_type[$value_type]
79 : array();
80 }
81 return $providers_by_type;
82 }
83
84 /**
85 * Retrieve a list of available value providers for the given value type,
86 * compatible for use in a 'select' type form element.
87 */
88 function value_provider_options($value_type) {
89 $providers = value_providers($value_type);
90 $provider_options = array();
91
92 foreach ($providers as $provider_name => $provider) {
93 $provider_options[$provider_name] = $provider['title'];
94 }
95 return $provider_options;
96 }
97
98 /**
99 * Retrieve a provider info array containing information about Views data,
100 * parse callback and more.
101 *
102 * @param $provider_name
103 * The name of the provider for which the provider info array should be
104 * retrieved.
105 * @param $value_type
106 * The given value type that is expected for this provider
107 * (e.g. 'nid' or 'hours').
108 */
109 function value_provider($provider_name, $value_type) {
110 $providers = value_providers($value_type);
111 return isset($providers[$provider_name]) ? $providers[$provider_name] : NULL;
112 }
113
114 /**
115 * Add all fields of a given provider to a view, so that those can later
116 * be transformed to a property of each result item.
117 */
118 function value_provider_add_fields(&$view, $display_id, $provider) {
119 $handler = &$view->display[$display_id]->handler;
120
121 foreach ($provider['columns'] as $column_property_name => $column_name) {
122 if (isset($provider['handler_name'][$column_name])) {
123 // Don't add additional columns, their handler is already
124 // being added by the main column (which is always specified).
125 continue;
126 }
127 $field_handler = views_get_handler(
128 $provider['views table'], $column_name, 'field'
129 );
130
131 if (array_key_exists($column_name, $view->get_items('field'))) {
132 $id = $column_name;
133 }
134 else if (is_object($field_handler) && !($field_handler instanceof views_handler_field_broken)) {
135 // Column is not yet in the view, we need to insert it.
136 // Only if the field handler actually exists, though.
137 $id = $view->add_item($display_id, 'field', $provider['views table'], $column_name);
138 }
139
140 $item = $view->get_item($display_id, 'field', $column_name);
141 if (!isset($item)) {
142 return FALSE;
143 }
144 $options = module_invoke_all('value_provider_field_handler_options', get_class($field_handler));
145 $item = array_merge($item, $options);
146 $view->set_item($display_id, 'field', $column_name, $item);
147 }
148 }
149
150 /**
151 * Transform the raw view results into an array of actual result objects
152 * or arrays by using the parse function of value providers.
153 *
154 * @param $view
155 * The view that has been executed and now contains its raw results
156 * in $view->result.
157 * @param $providers
158 * The value providers whose fields have been added to the view
159 * with value_provider_add_fields(). The array key of this list will
160 * determine the name of the corresponding result properties.
161 * @param $primary_key
162 * The view's primary key, e.g. 'nid' for node views or 'uid' for user views.
163 * @param $result_type
164 * If 'object' (default), this function will return an array of
165 * result objects. If 'array', it will return an array of arrays.
166 * Either way, the container array is keyed by the $primary_key,
167 * and also contains the $primary_key as property / array element.
168 */
169 function value_provider_results($view, $providers, $primary_key, $result_type = 'object') {
170 $results = array();
171 foreach ($view->result as $row) {
172 $results[$row->$primary_key] = array(
173 $primary_key => $row->$primary_key,
174 );
175 if ($result_type == 'object') {
176 $results[$row->$primary_key] = (object) $results[$row->$primary_key];
177 }
178 $results[$row->$primary_key] = value_provider_merge_properties(
179 $view, $row, $results[$row->$primary_key], $providers
180 );
181 }
182 return $results;
183 }
184
185 /**
186 * Transform one raw view result into actual result properties by using
187 * the parse function of value providers, and merge these result properties
188 * into an existing object or array.
189 *
190 * @param $view
191 * The view that has been executed.
192 * @param $result
193 * A single result row of $view->result from the above view.
194 * @param $target
195 * The object or array that shall receive the parsed result properties.
196 * @param $providers
197 * The value providers whose fields have been added to the view
198 * with value_provider_add_fields(). The array key of this list will
199 * determine the name of the corresponding result properties.
200 * @return
201 * The $target object or array, extended by the additional result properties.
202 */
203 function value_provider_merge_properties($view, $result, &$target, $providers) {
204 foreach ($providers as $value_name => $provider) {
205 $value_properties = array();
206
207 foreach ($provider['columns'] as $value_property_name => $column_name) {
208 $handler_name = isset($provider['handler_name'][$column_name])
209 ? $provider['handler_name'][$column_name]
210 : $column_name;
211
212 $field_handler = $view->field[$handler_name];
213 $result_column = $field_handler->aliases[$column_name];
214
215 if (isset($result->$result_column)) {
216 $value_properties[$value_property_name] = $result->$result_column;
217 }
218 }
219 $parse_function = $provider['parse callback'];
220
221 if (is_object($target)) {
222 $target->$value_name = $parse_function($value_properties);
223 }
224 else {
225 $target[$value_name] = $parse_function($value_properties);
226 }
227 }
228 return $target;
229 }
230
231 /**
232 * Add a filter defined by a value provider to a view.
233 *
234 * @return
235 * TRUE if the filter was added successfully, or FALSE otherwise.
236 */
237 function value_provider_add_filter(&$view, $display_id, $provider, $filter_id, $filter_options = NULL) {
238 $handler = &$view->display[$display_id]->handler;
239
240 $filter_name = $provider['filters'][$filter_id]['field'];
241 $filter_handler = views_get_handler($provider['views table'], $filter_name, 'filter');
242
243 if (!$filter_handler) {
244 return FALSE;
245 }
246 // Add the filter to the view.
247 $id = $view->add_item($display_id, 'filter', $provider['views table'], $filter_name);
248 $filters = $handler->get_option('filters');
249
250 $filter_function = $provider['filters'][$filter_id]['callback'];
251 $filter_function($filters[$id], $filter_handler, $filter_options);
252
253 $handler->set_option('filters', $filters);
254 return TRUE;
255 }
256
257
258 /**
259 * Implementation of hook_nodeapi(): Let value providers specify if they want
260 * to cause a hook_value_provider_[valuetype]_modified() call, which should
261 * happen when the value inside a node has been inserted, updated or deleted.
262 */
263 function value_provider_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
264 switch ($op) {
265 case 'insert':
266 case 'update':
267 case 'delete':
268 $modified_providers = array();
269
270 foreach (value_providers() as $value_type => $providers) {
271 $notification_functions = array();
272 foreach ($providers as $provider_name => $provider) {
273 if (!empty($provider['nodeapi notifications'])) {
274 $notification_functions[$provider['nodeapi notifications']][$provider_name] = $provider;
275 }
276 }
277 if (!empty($notification_functions)) {
278 $modified_providers[$value_type] = array();
279
280 foreach ($notification_functions as $function => $function_providers) {
281 $function = $provider['nodeapi notifications'];
282 $modified_providers[$value_type] += $function($node, $op, $value_type, $providers);
283 }
284 }
285 }
286
287 if (!empty($modified_providers)) {
288 module_invoke_all('value_provider_modified', $node, $op, $modified_providers);
289 }
290 break;
291 }
292 }
293
294 /**
295 * Return a skeleton for CCK based value providers, with important stuff
296 * like tables, columns and title already filled in. The 'parse callback'
297 * and (optional) 'filters' properties are still missing from that array,
298 * those need to be added manually before adding the provider to the
299 * provider info array.
300 */
301 function value_provider_content_provider_base($field) {
302 $field_db_info = content_database_info($field);
303
304 $provider = array(
305 'title' => value_provider_content_field_title($field),
306 'views table' => content_views_tablename($field),
307 'nodeapi notifications' => 'value_provider_content_nodeapi_notification',
308 'extra' => array('cck field' => $field),
309 );
310
311 foreach ($field_db_info['columns'] as $column_name => $column_info) {
312 $provider['columns'][$column_name] = $column_info['column'];
313
314 // CCK only provides a single handler that makes use of additional columns,
315 // and that one has the name of the first column. All other columns also
316 // need to specify that handler, and be added as additional columns to it.
317 if (!isset($first_column)) {
318 $first_column = $column_info['column'];
319 }
320 else {
321 $provider['handler_name'][$column_info['column']] = $first_column;
322 }
323 }
324 return $provider;
325 }
326
327 /**
328 * Return a list of providers whose values have been modified on a
329 * hook_nodeapi() insert, update or delete operation.
330 */
331 function value_provider_content_nodeapi_notification($node, $op, $value_type, $providers) {
332 $modified_providers = array();
333
334 foreach ($providers as $provider_name => $provider) {
335 $field_name = $provider['extra']['cck field']['field_name'];
336 $field = content_fields($field_name, $node->type);
337
338 if (!empty($field)) {
339 $modified_providers[$provider_name] = $provider;
340 }
341 }
342 return $modified_providers;
343 }
344
345 /**
346 * Return a user visible string representation for a given CCK field.
347 */
348 function value_provider_content_field_title($field) {
349 $label = $field['widget']['label'];
350
351 if (empty($label)) {
352 return $field['field_name'];
353 }
354 else {
355 return t('@label (@fieldname)', array(
356 '@label' => $label, '@fieldname' => $field['field_name']
357 ));
358 }
359 }
360
361 /**
362 * Implementation of hook_value_provider_field_handler_options():
363 * Provide default options for field handlers.
364 */
365 function value_provider_value_provider_field_handler_options($handler_class) {
366 switch ($handler_class) {
367 case 'content_handler_field_multiple':
368 return array(
369 'multiple' => array(
370 'group' => FALSE,
371 ),
372 );
373 }
374 }

  ViewVC Help
Powered by ViewVC 1.1.2