/[drupal]/contributions/modules/bio/bio_views.inc
ViewVC logotype

Diff of /contributions/modules/bio/bio_views.inc

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

revision 1.1, Sat May 26 00:06:47 2007 UTC revision 1.2, Sat Apr 11 01:32:50 2009 UTC
# Line 0  Line 1 
1    <?php
2    // $Id: bio_views.inc,v 1.1.2.7 2008/03/19 18:46:38 dww Exp $
3    
4    /**
5     * @file
6     * Views integration for Bio module.
7     *
8     * The Bio module integrates with Views by re-exposing the Bio node for an
9     * author as part of any Views query.
10     *
11     * For example, it is possible to perform queries like:
12     * - Find all blog posts by authors who have Bio nodes tagged with the term
13     *   "kayaking."
14     * - Find all the Bio nodes by authors who have a first name (where "first
15     *   name" is a field) like "joe."
16     * - Find all the forum posts by the most popular authors, ranked by most
17     *   viewed Bio pages.
18     *
19     * This file also provides two filters:
20     * - Node: Type is Bio node:
21     *   This is useful for shipping premade views that rely on Bio, but are not
22     *   tied to a particular type of node acting as the Bio node (e.g. on one site
23     *   it might be "Biography," and on another "profile").
24     * - Bio: Author has Bio node:
25     *   This is useful for only returning results where the author has created a
26     *   Bio node. That way, if you are exposing Bio fields (e.g. the "interests"
27     *   taxonomy), you can be sure that a Bio node exists for every other node
28     *   returned in the query.
29     *
30     * See the README for more information on creating Views with Bio information.
31     */
32    
33    /**
34     * Real implementation of hook_views_table_alter().
35     */
36    function _bio_views_tables_alter(&$tables) {
37      // Amass some data to use later.
38      $bio_type = bio_get_type();
39      $bio_name = node_get_types('name', $bio_type);
40    
41      if (module_exists('taxonomy')) {
42        $vocabs = array_keys(taxonomy_get_vocabularies($bio_type));
43      }
44    
45      // Fetch some CCK info if CCK is installed.
46      $bio_fields = array();
47      if (module_exists('content')) {
48        $content_type_info = content_types($bio_type);
49        if (is_array($content_type_info['fields'])) {
50          $bio_fields = array_keys($content_type_info['fields']);
51        }
52      }
53    
54      // The first step is to copy the node table and alias it as the "node" table.
55      // This allows us to access all node table data. Later, we can point other
56      // modules at the "bio" table and it will behave just like the node table.
57      $old_node = $tables['node'];
58      // TODO: Not sure what this does, remove it.
59      unset($old_node['provider']);
60      $old_node['join'] = array(
61        // TODO: Default option is left. I think inner is probably better?
62        //'type' => 'inner',
63        'left' => array(
64          'table' => 'node',
65          'field' => 'uid'
66        ),
67        'right' => array(
68          'field' => 'uid'
69        ),
70        'extra' => array(
71          // TODO: Will I need to specify bio.type instead of type?
72          'type' => $bio_type,
73        ),
74      );
75    
76      // Remove some fields, filters, and sorts that don't make sense for a joined
77      // Bio table.
78    
79      // Node: Type.
80      unset($old_node['fields']['type']);
81      // Node: Type.
82      unset($old_node['filters']['type']);
83      // Node: Author is anonymous.
84      unset($old_node['filters']['anon']);
85      // Node: Author is current user.
86      unset($old_node['filters']['currentuid']);
87      // Node: Current user authored or commented.
88      unset($old_node['filters']['currentuidtouched']);
89      // Node: Type.
90      unset($old_node['sorts']['type']);
91      // Node: Random.
92      unset($old_node['sorts']['random']);
93    
94      // For bio_node, nid is a real column.
95      unset($old_node['fields']['nid']['notafield']);
96    
97      // Prefix descriptions with "Bio:" to differentiate them from standard stuff.
98      _bio_rename_table_labels($old_node, $bio_name);
99    
100      // Save our worked up node table back in the array.
101      $tables['bio'] = $old_node;
102    
103      // Bio copies all other tables and renames them bio_foo. This allows us to
104      // re-expose all the data of the Bio node in a forward compatible,
105      // transparent manner. We assume all tables connect to node (via
106      // intermediate tables). For now, a safe assumption.
107    
108      // Without this copy, Apache would spin off and die a horrible death.
109      $table_copy = $tables;
110      foreach ($table_copy as $name => $data) {
111    
112        // We can skip the node and bio tables. Other tables can be skipped, too.
113        // TODO: Is there a use case for including comments? Comment stats are
114        // pretty useful, but do we really need: "show me the comments on the
115        // profiles of authors who wrote a blog post about foo?"
116        if (in_array($name, array('node', 'bio', 'users', 'users_roles', 'comments', 'book', 'book_parent_node', 'temp_search_results'))) {
117          continue;
118        }
119    
120        // skip anything that joins against UID, we don't need that (e.g. profile_xxx)
121        if ($data['join']['left']['table'] == 'node' && $data['join']['left']['field'] == 'uid') {
122          continue;
123        }
124    
125        // we should skip tables that don't relate to bio node types specifically
126        // e.g. taxonomy vocabs that don't apply, cck fields that aren't in the bio node type, etc.
127    
128        // Skip unneeded taxonomy vocabularies.
129        if (strpos($name, 'term_node_') === 0) {
130          $vid = substr($name, 10);
131          if (!in_array($vid, $vocabs)) {
132            continue;
133          }
134        }
135        // Skip fields not assigned to the Bio node type.
136        elseif (strpos($name, 'node_data_') === 0) {
137          $field = substr($name, 10);
138          if (!in_array($field, $bio_fields)) {
139            continue;
140          }
141        }
142    
143        // If the table joins directly to node, make it's new join point "bio."
144        // If it joins against something else, assume that we'll create a "bio_X"
145        // for it at some point.
146        if ($data['join']['left']['table'] == 'node') {
147          $data['join']['left']['table'] = 'bio';
148        }
149        else {
150          $data['join']['left']['table'] = 'bio_'. $data['join']['left']['table'];
151        }
152        _bio_rename_table_labels($data, $bio_name);
153        $tables["bio_$name"] = $data;
154      }
155    
156      // Now that all the bio_* tables are ready, add some other useful filters to
157      // the mix.
158    
159      // Node: Type is Bio node -- cribbed from views_node.inc.
160      $tables['node']['filters']['biotype'] = array(
161        'field' => 'type',
162        'name' => t('Node: Type is Bio node'),
163        'operator' => array('=' => t('Is'), '!=' => t('Is not')),
164        'value' => _bio_provide_hidden_form($bio_type, $bio_name),
165        'help' => t('This allows you to filter by whether or not the node is a bio node. Select "Is" to limit to bio nodes, select "is not" to limit to all other content types'),
166      );
167    
168      // Bio: Author has a Bio -- limits the results (e.g. blog posts) to those
169      // where the author has a Bio. Relies on http://drupal.org/node/142504.
170      $tables['bio']['filters']['author_has_bio'] = array(
171        'field' => 'uid',
172        'name' => t('Bio: Author has a Bio'),
173        'operator' => array('IS NOT' => t('Does'), 'IS' => t('Does not')),
174        'value' => _bio_provide_hidden_form(NULL, t('Have a bio node')),
175        'help' => t('Filter in only nodes for which the author has or does not have a bio node.'),
176        'handler' => 'views_handler_filter_null',
177      );
178    
179      // Override the default handler on the "is new" filter, as it needs some very
180      // specific table names.
181      $tables['bio_history']['filters']['timestamp']['handler'] = 'bio_handler_filter_isnew';
182    }
183    
184    /**
185     * Helper function to rename Node: Title => Bio: Node: Title, etc.
186     */
187    function _bio_rename_table_labels(&$table, $bio_name) {
188      foreach (array('fields', 'sorts', 'filters') as $section) {
189        if (is_array($table[$section])) {
190          foreach ($table[$section] as $id => $object) {
191            $table[$section][$id]['name'] = $bio_name .': '. $object['name'];
192          }
193        }
194      }
195    }
196    
197    /**
198     * Used to force the value of certain form fields by converting to markup.
199     */
200    function _bio_provide_hidden_form($value, $markup) {
201      $form['text'] = array(
202        '#type' => 'markup',
203        '#value' => $markup,
204      );
205      $form['value'] = array(
206        '#type' => 'value',
207        '#value' => $value,
208      );
209    
210      return $form;
211    }
212    
213    /**
214     * Custom filter for new content. Copied directly from views_node.inc and modified to use bio_* tables.
215     */
216    function _bio_handler_filter_isnew($op, $filter, $filterinfo, &$query) {
217      global $user;
218      if (!$user || !$user->uid) {
219        return;
220      }
221    
222      // Hey, Drupal kills old history, so nodes that haven't been updated
223      // since NODE_NEW_LIMIT are bzzzzzzzt outta here!
224    
225      $limit = time() - NODE_NEW_LIMIT;
226    
227      $query->ensure_table('bio_history');
228      if (module_exists('comment')) {
229        $query->ensure_table('bio_node_comment_statistics');
230        $clause = ("OR bio_node_comment_statistics.last_comment_timestamp > (***CURRENT_TIME*** - $limit)");
231        $clause2 = "OR bio_history.timestamp < bio_node_comment_statistics.last_comment_timestamp";
232      }
233    
234      // NULL means a history record doesn't exist. That's clearly new content.
235      // Unless it's very very old content. Everything in the query is already
236      // type safe cause none of it is coming from outside here.
237      $query->add_where("(bio_history.timestamp IS NULL AND (bio.changed > (***CURRENT_TIME***-$limit) $clause)) OR bio_history.timestamp < bio.changed $clause2");
238    }
239    
240    /**
241     * Real implementation of hook_views_query_alter().
242     *
243     * For any bio_* table, we need to make sure the bio_nid is added.
244     */
245    function _bio_views_query_alter(&$query, $view, $summary, $level) {
246      // See if we need to add the Bio module.
247      if (_bio_should_add_nid($query, $view)) {
248        $query->ensure_table('bio');
249        $query->add_field('nid', 'bio', 'bio_nid');
250      }
251    }
252    
253    /**
254     * Helper function to determine if we need bio.nid in the query.
255     *
256     * @todo This looks like a bit of a hack. What happens if I install the biology
257     * module? :P
258     */
259    function _bio_should_add_nid($query, $view) {
260      foreach ($view->field as $field) {
261        if (strpos($field['tablename'], 'bio') === 0) {
262          return true;
263        }
264      }
265    
266      foreach ($view->filter as $filter) {
267        if (strpos($filter['tablename'], 'bio') === 0) {
268          return true;
269        }
270      }
271    
272      return false;
273    }
274    
275    /**
276     * Real implemenation of hook_views_default_tables().
277     *
278     * Default views are:
279     * - recent_biographies:
280     *   A listing of teasers of recent Bio nodes, regradless of what the Bio node
281     *   type is.
282     * - author_tracker:
283     *   Just like the usual tracker, but using Bio node titles instead of the user
284     *   name for the "author" column.
285     *
286     * These Views are disabled by default.
287     */
288    function _bio_views_default_views() {
289      // A little set up to make these views look nicer :-)
290      $bio_type = bio_get_type();
291      $bio_name = node_get_types('name', $bio_type);
292    
293      $view = new stdClass();
294      $view->disabled = true;
295      $view->name = 'recent_biographies';
296      $view->description = 'A list of recently created biographies, from the bio module. The url changes to whatever your bio node type is, as does the title.';
297      $view->access = array(
298      );
299      $view->view_args_php = '';
300      $view->page = TRUE;
301      $view->page_title = "Recent $bio_name Entries";
302      $view->page_header = '';
303      $view->page_header_format = '1';
304      $view->page_footer = '';
305      $view->page_footer_format = '1';
306      $view->page_empty = '';
307      $view->page_empty_format = '1';
308      $view->page_type = 'teaser';
309      $view->url = $bio_type;
310      $view->use_pager = TRUE;
311      $view->nodes_per_page = '10';
312      $view->sort = array(
313        array(
314          'tablename' => 'node',
315          'field' => 'created',
316          'sortorder' => 'DESC',
317          'options' => 'normal',
318        ),
319      );
320      $view->argument = array(
321      );
322      $view->field = array(
323      );
324      $view->filter = array(
325        array(
326          'tablename' => 'node',
327          'field' => 'biotype',
328          'operator' => '=',
329          'options' => '',
330          'value' => 'bio',
331        ),
332      );
333      $view->exposed_filter = array(
334      );
335      $view->requires = array(node);
336      $views[$view->name] = $view;
337    
338      $view = new stdClass();
339      $view->disabled = true;
340      $view->name = 'tracker_bio';
341      $view->description = 'Shows all new activity on system using the bio node title as the author name.';
342      $view->access = array(
343      );
344      $view->view_args_php = '';
345      $view->page = TRUE;
346      $view->page_title = 'Recent posts';
347      $view->page_header = '';
348      $view->page_header_format = '1';
349      $view->page_footer = '';
350      $view->page_footer_format = '1';
351      $view->page_empty = '';
352      $view->page_empty_format = '1';
353      $view->page_type = 'table';
354      $view->url = 'tracker';
355      $view->use_pager = TRUE;
356      $view->nodes_per_page = '25';
357      $view->menu = TRUE;
358      $view->menu_title = 'Recent posts';
359      $view->menu_tab = FALSE;
360      $view->menu_tab_weight = '0';
361      $view->menu_tab_default = FALSE;
362      $view->menu_tab_default_parent = NULL;
363      $view->menu_parent_tab_weight = '0';
364      $view->menu_parent_title = '';
365      $view->sort = array(
366        array(
367          'tablename' => 'node_comment_statistics',
368          'field' => 'last_comment_timestamp',
369          'sortorder' => 'DESC',
370          'options' => 'normal',
371        ),
372      );
373      $view->argument = array(
374        array(
375          'type' => 'uid',
376          'argdefault' => '2',
377          'title' => 'recent posts for %1',
378          'options' => '',
379          'wildcard' => '',
380          'wildcard_substitution' => '',
381        ),
382      );
383      $view->field = array(
384        array(
385          'tablename' => 'node',
386          'field' => 'type',
387          'label' => 'Type',
388        ),
389        array(
390          'tablename' => 'node',
391          'field' => 'title',
392          'label' => 'Title',
393          'handler' => 'views_handler_field_nodelink_with_mark',
394          'options' => 'link',
395        ),
396        array(
397          'tablename' => 'bio',
398          'field' => 'title',
399          'label' => 'Author',
400          'handler' => 'views_handler_field_nodelink',
401          'options' => 'link',
402        ),
403        array(
404          'tablename' => 'node_comment_statistics',
405          'field' => 'comment_count',
406          'label' => 'Replies',
407          'handler' => 'views_handler_comments_with_new',
408        ),
409        array(
410          'tablename' => 'node_comment_statistics',
411          'field' => 'last_comment_timestamp',
412          'label' => 'Last Post',
413          'handler' => 'views_handler_field_since',
414        ),
415      );
416      $view->filter = array(
417        array(
418          'tablename' => 'node',
419          'field' => 'status',
420          'operator' => '=',
421          'options' => '',
422          'value' => '1',
423        ),
424        array(
425          'tablename' => 'node',
426          'field' => 'biotype',
427          'operator' => '!=',
428          'options' => '',
429          'value' => 'bio',
430        ),
431      );
432      $view->exposed_filter = array(
433      );
434      $view->requires = array(node_comment_statistics, node, bio);
435      $views[$view->name] = $view;
436    
437      return $views;
438    }
439    
440    /**
441     * Real implemenation of hook_views_tables().
442     *
443     * Exposes data from the {user} table, such as the full username, account
444     * status, e-mail address, etc, to views of the corresponding bio nodes.
445     */
446    function _bio_views_tables() {
447      $tables['bio'] = array(
448        'name' => 'bio',
449        'join' => array(
450          'type' => 'inner',
451          'left' => array(
452            'table' => 'node',
453            'field' => 'nid'
454          ),
455          'right' => array(
456            'field' => 'nid'
457          ),
458        ),
459      );
460      $tables['bio_users'] = array(
461        'name' => 'users',
462        'join' => array(
463          'type' => 'inner',
464          'left' => array(
465            'table' => 'bio',
466            'field' => 'uid'
467          ),
468          'right' => array(
469            'field' => 'uid'
470          ),
471        ),
472        'fields' => array(
473          'name' => array(
474            'name' => t('Bio: User: Username'),
475            'uid' => 'uid',
476            'addlfields' => array('uid'),
477            'sortable' => TRUE,
478            'help' => t('The username of the user associated with a given bio.'),
479            'handler' => 'views_handler_field_username',
480          ),
481          'mail' => array(
482            'name' => t('Bio: User: E-mail'),
483            'handler' => 'views_handler_field_email',
484            'help' => t('The e-mail address of the user associated with a given bio.'),
485            'sortable' => TRUE,
486          ),
487          'status' => array(
488            'name' => t('Bio: User: Account status'),
489            'help' => t('The account status of the user associated with a given bio.'),
490            'handler' => 'bio_views_handler_field_user_status',
491            'sortable' => TRUE,
492          ),
493          'picture' => array(
494            'name' => t('Bio: User: Picture'),
495            'field' => 'uid',
496            'help' => t('The picture of the user associated with a given bio.'),
497            'handler' => 'views_handler_field_userpic',
498            'sortable' => FALSE,
499          ),
500          'signature' => array(
501            'name' => t('Bio: User: Signature'),
502            'help' => t('The signature of the user associated with a given bio.'),
503            'sortable' => FALSE,
504          ),
505          'created' => array(
506            'name' => t('Bio: User: Created time'),
507            'help' => t("The creation time of the user associated with a given bio. The option field may be used to specify the custom date format as it's required by the date() function or if 'as time ago' has been chosen to customize the granularity of the time interval."),
508            'handler' => views_handler_field_dates(),
509            'option' => 'string',
510            'sortable' => TRUE,
511          ),
512          'access' => array(
513            'name' => t('Bio: User: Access time'),
514            'help' => t("The last access time of the user associated with a given bio. The option field may be used to specify the custom date format as it's required by the date() function or if 'as time ago' has been chosen to customize the granularity of the time interval."),
515            'handler' => views_handler_field_dates(),
516            'option' => 'string',
517            'sortable' => TRUE,
518          ),
519          'login' => array(
520            'name' => t('Bio: User: Login time'),
521            'help' => t("The last login time of the user associated with a given bio. The option field may be used to specify the custom date format as it's required by the date() function or if 'as time ago' has been chosen to customize the granularity of the time interval."),
522            'handler' => views_handler_field_dates(),
523            'option' => 'string',
524            'sortable' => TRUE,
525          ),
526        ),
527      );
528      return $tables;
529    }
530    
531    function bio_views_handler_field_user_status($fieldinfo, $fielddata, $value, $data) {
532      return $value == 0 ? t('Blocked') : t('Active');
533    }
534    
535    if (!function_exists('views_handler_field_email')) {
536      function views_handler_field_email($fieldinfo, $fielddata, $value, $data) {
537        return l($value, 'mailto:' . $value);
538      }
539    }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2

  ViewVC Help
Powered by ViewVC 1.1.2