Some code re-org to reduce the weight of views.module
[project/views.git] / views.module
1 <?php
2 // $Id$
3 /**
4 * @file
5 * Primarily Drupal hooks and global API functions to manipulate views.
6 *
7 * This is the main module file for Views. The main entry points into
8 * this module are views_page() and views_block(), where it handles
9 * incoming page and block requests.
10 */
11
12 /**
13 * Implementation of hook_theme(). Register views theming functions.
14 */
15 function views_theme() {
16 $path = drupal_get_path('module', 'views');
17 require_once "./$path/theme/theme.inc";
18
19 // Some quasi clever array merging here.
20 $base = array(
21 'file' => 'theme.inc',
22 'path' => "$path/theme",
23 );
24
25 // Our extra version of pager from pager.inc
26 $hooks['views_mini_pager'] = $base + array(
27 'arguments' => array('tags' => array(), 'limit' => 10, 'element' => 0, 'parameters' => array()),
28 );
29
30 $arguments = array(
31 'display' => array('view' => NULL),
32 'style' => array('view' => NULL, 'options' => NULL, 'rows' => NULL),
33 'row' => array('view' => NULL, 'options' => NULL, 'row' => NULL),
34 );
35
36 // Default view themes
37 $hooks['views_view_field'] = $base + array(
38 'pattern' => 'views_view_field__',
39 'arguments' => array('view' => NULL, 'field' => NULL, 'row' => NULL),
40 );
41
42 $plugins = views_fetch_plugin_data();
43
44 // Register theme functions for all style plugins
45 foreach ($plugins as $type => $info) {
46 foreach ($info as $plugin => $def) {
47 if (isset($def['theme'])) {
48 $hooks[$def['theme']] = array(
49 'pattern' => $def['theme'] . '__',
50 'file' => $def['file'],
51 'path' => $def['path'],
52 'arguments' => $arguments[$type],
53 );
54 if (!function_exists('theme_' . $def['theme'])) {
55 $hooks[$def['theme']]['template'] = views_css_safe($def['theme']);
56 }
57 }
58 if (isset($def['additional themes'])) {
59 foreach ($def['additional themes'] as $theme => $theme_type) {
60 if (empty($theme_type)) {
61 $theme = $theme_type;
62 $theme_type = $type;
63 }
64
65 $hooks[$theme] = array(
66 'pattern' => $theme . '__',
67 'file' => $def['file'],
68 'path' => $def['path'],
69 'arguments' => $arguments[$theme_type],
70 );
71 if (!function_exists('theme_' . $theme)) {
72 $hooks[$theme]['template'] = views_css_safe($theme);
73 }
74 }
75 }
76 }
77 }
78
79 $hooks['views_exposed_form'] = $base + array(
80 'template' => 'views-exposed-form',
81 'pattern' => 'views_exposed_form__',
82 'arguments' => array('form' => NULL),
83 );
84
85 $hooks['views_more'] = $base + array(
86 'template' => 'views-more',
87 'pattern' => 'views_more__',
88 'arguments' => array('more_url' => NULL),
89 );
90
91 return $hooks;
92 }
93
94 /**
95 * Implementation of hook_menu().
96 */
97 function views_menu() {
98 // Any event which causes a menu_rebuild could potentially mean that the
99 // Views data is updated -- module changes, profile changes, etc.
100 views_invalidate_cache();
101 $items = array();
102 $items['views/ajax'] = array(
103 'title' => 'Views',
104 'page callback' => 'views_ajax',
105 'file' => 'includes/ajax.inc',
106 'access callback' => 'user_access',
107 'access arguments' => array('access content'),
108 'description' => 'Ajax callback for view loading.',
109 'type' => MENU_CALLBACK,
110 );
111 return $items;
112 }
113
114 /**
115 * Implementation of hook_menu_alter().
116 */
117 function views_menu_alter(&$callbacks) {
118 $our_paths = array();
119 foreach (views_get_applicable_views('uses hook menu') as $data) {
120 list($view, $display_id) = $data;
121 $result = $view->execute_hook_menu($display_id);
122 if (is_array($result)) {
123 // The menu system doesn't support having two otherwise
124 // identical paths with different placeholders. So we
125 // want to remove the existing items from the menu whose
126 // paths would conflict with ours.
127
128 // First, we must find any existing menu items that may
129 // conflict. We use a regular expression because we don't
130 // know what placeholders they might use. Note that we
131 // first construct the regex itself by replacing %views_arg
132 // in the display path, then we use this constructed regex
133 // (which will be something like '#^(foo/%[^/]*/bar)$#') to
134 // search through the existing paths.
135 $regex = '#^('. preg_replace('#%views_arg#', '%[^/]*', implode('|', array_keys($result))) .')$#';
136 $matches = preg_grep($regex, array_keys($callbacks));
137
138 // Remove any conflicting items that were found.
139 foreach ($matches as $path) {
140 // Don't remove the paths we just added!
141 if (!isset($our_paths[$path])) {
142 unset($callbacks[$path]);
143 }
144 }
145 foreach ($result as $path => $item) {
146 if (!isset($callbacks[$path])) {
147 // Add a new item, possibly replacing (and thus effectively
148 // overriding) one that we removed above.
149 $callbacks[$path] = $item;
150 }
151 else {
152 // This item already exists, so it must be one that we added.
153 // We change the various callback arguments to pass an array
154 // of possible display IDs instead of a single ID.
155 $callbacks[$path]['page arguments'][1] = (array)$callbacks[$path]['page arguments'][1];
156 $callbacks[$path]['page arguments'][1][] = $display_id;
157 $callbacks[$path]['access arguments'][0][1] = (array)$callbacks[$path]['access arguments'][0][1];
158 $callbacks[$path]['access arguments'][0][1][] = $display_id;
159 $callbacks[$path]['load arguments'][1] = (array)$callbacks[$path]['load arguments'][1];
160 $callbacks[$path]['load arguments'][1][] = $display_id;
161 }
162 $our_paths[$path] = TRUE;
163 }
164 }
165 }
166 }
167
168 /**
169 * Helper function for menu loading. This will automatically be
170 * called in order to 'load' a views argument; primarily it
171 * will be used to perform validation.
172 *
173 * @param $value
174 * The actual value passed.
175 * @param $name
176 * The name of the view. This needs to be specified in the 'load function'
177 * of the menu entry.
178 * @param $index
179 * The menu argument index. This counts from 1.
180 */
181 function views_arg_load($value, $name, $display_id, $index) {
182 if ($view = views_get_view($name)) {
183 $view->set_display($display_id);
184 $view->init_handlers();
185
186 $ids = array_keys($view->argument);
187
188 $indexes = array();
189 $path = explode('/', $view->get_url());
190 foreach ($path as $id => $piece) {
191 if ($piece == '%' && !empty($ids)) {
192 $indexes[$id] = array_shift($ids);
193 }
194 }
195
196 if (isset($indexes[$index])) {
197 if (isset($view->argument[$indexes[$index]])) {
198 return $view->argument[$indexes[$index]]['handler']->validate_argument($value) ? $value : NULL;
199 }
200 }
201 }
202 }
203
204 /**
205 * Page callback entry point; requires a view and a display id, then
206 * passes control to the display handler.
207 */
208 function views_page() {
209 $args = func_get_args();
210 $name = array_shift($args);
211 $display_id = array_shift($args);
212
213 // Load the view
214 if ($view = views_get_view($name)) {
215 return $view->execute_display($display_id, $args);
216 }
217
218 // Fallback; if we get here no view was found or handler was not valid.
219 return drupal_not_found();
220 }
221
222 /**
223 * Implementation of hook_block
224 */
225 function views_block($op = 'list', $delta = 0, $edit = array()) {
226 switch ($op) {
227 case 'list':
228 $items = array();
229 foreach (views_get_applicable_views('uses hook block') as $data) {
230 list($view, $display_id) = $data;
231 $result = $view->execute_hook_block($display_id);
232 if (is_array($result)) {
233 $items = array_merge($items, $result);
234 }
235 }
236
237 // block.module has a delta length limit of 32, but our deltas can
238 // unfortunately be longer because view names can be 32 and display IDs
239 // can also be 32. So for very long deltas, change to md5 hashes.
240 $hashes = array();
241
242 // get the keys because we're modifying the array and we don't want to
243 // confuse PHP too much.
244 $keys = array_keys($items);
245 foreach ($keys as $delta) {
246 if (strlen($delta) >= 32) {
247 $hash = md5($delta);
248 $hashes[$hash] = $delta;
249 $items[$hash] = $items[$delta];
250 unset($items[$delta]);
251 }
252 }
253
254 variable_set('views_block_hashes', $hashes);
255 return $items;
256 case 'view':
257 // if this is 32, this should be an md5 hash.
258 if (strlen($delta) == 32) {
259 $hashes = variable_get('views_block_hashes', array());
260 if (!empty($hashes[$delta])) {
261 $delta = $hashes[$delta];
262 }
263 }
264
265 list($name, $display_id) = explode('-', $delta);
266 // Load the view
267 if ($view = views_get_view($name)) {
268 if ($view->access($display_id)) {
269 return $view->execute_display($display_id);
270 }
271 }
272 break;
273 }
274 }
275
276 /**
277 * Implementation of hook_flush_caches().
278 */
279 function views_flush_caches() {
280 return array('cache_views');
281 }
282
283 /**
284 * Invalidate the views cache, forcing a rebuild on the next grab of table data.
285 */
286 function views_invalidate_cache() {
287 cache_clear_all('*', 'cache_views', true);
288 }
289
290 /**
291 * Determine if the given user has access to the view + display.
292 *
293 * @param $view
294 * May be a view object, or an array with the view name and the display ID,
295 * or a string to use as the view name.
296 * @param $account
297 * An optional account to use; if left off, the current user will be used.
298 */
299 function views_access($view, $account = NULL) {
300 if (is_array($view)) {
301 list($name, $display_id) = $view;
302 $view = views_get_view($name);
303 if (!$view) {
304 return FALSE;
305 }
306 }
307 elseif (is_string($view)) {
308 $view = views_get_view($view);
309 if (!$view) {
310 return FALSE;
311 }
312 $display_id = 'default';
313 }
314 else {
315 // Clone the view to prevent problems.
316 $view = $view->clone_view();
317 $display_id = isset($view->current_display) ? $view->current_display : 'default';
318 }
319
320 return $view->access($display_id, $account);
321 }
322
323 // ------------------------------------------------------------------
324 // Functions to help identify views that are running or ran
325
326 /**
327 * Set the current 'page view' that is being displayed so that it is easy
328 * for other modules or the theme to identify.
329 */
330 function &views_set_page_view($view = NULL) {
331 static $cache = NULL;
332 if (isset($view)) {
333 $cache = $view;
334 }
335
336 return $cache;
337 }
338
339 /**
340 * Find out what, if any, page view is currently in use. Please note that
341 * this returns a reference, so be careful! You can unintentionally modify the
342 * $view object.
343 */
344 function &views_get_page_view() {
345 return views_set_page_view();
346 }
347
348 /**
349 * Set the current 'current view' that is being built/rendered so that it is
350 * easy for other modules or items in drupal_eval to identify
351 */
352 function &views_set_current_view($view = NULL) {
353 static $cache = NULL;
354 if (isset($view)) {
355 $cache = $view;
356 }
357
358 return $cache;
359 }
360
361 /**
362 * Find out what, if any, current view is currently in use. Please note that
363 * this returns a reference, so be careful! You can unintentionally modify the
364 * $view object.
365 */
366 function &views_get_current_view() {
367 return views_set_current_view();
368 }
369
370 // ------------------------------------------------------------------
371 // Include file helpers
372
373 /**
374 * Include views .inc files as necessary.
375 */
376 function views_include($file) {
377 static $used = array();
378 if (!isset($used[$file])) {
379 require_once './' . drupal_get_path('module', 'views') . "/includes/$file.inc";
380 }
381
382 $used[$file] = TRUE;
383 }
384
385 /**
386 * Load views files on behalf of modules.
387 */
388 function views_module_include($file) {
389 $views_path = drupal_get_path('module', 'views') . '/modules';
390 foreach (module_list() as $module) {
391 $module_path = drupal_get_path('module', $module);
392 if (file_exists("$module_path/$module.$file")) {
393 require_once "./$module_path/$module.$file";
394 }
395 else if (file_exists("$module_path/includes/$module.$file")) {
396 require_once "./$module_path/includes/$module.$file";
397 }
398 else if (file_exists("$views_path/$module.$file")) {
399 require_once "./$views_path/$module.$file";
400 }
401 }
402 }
403
404 /**
405 * Include views .css files.
406 */
407 function views_add_css($file) {
408 drupal_add_css(drupal_get_path('module', 'views') . "/css/$file.css");
409 }
410
411 /**
412 * Include views .js files.
413 */
414 function views_add_js($file) {
415 static $base = TRUE;
416 if ($base) {
417 drupal_add_js(drupal_get_path('module', 'views') . "/js/base.js");
418 }
419 drupal_add_js(drupal_get_path('module', 'views') . "/js/$file.js");
420 }
421
422 /**
423 * Load views files on behalf of modules.
424 */
425 function views_include_handlers() {
426 static $finished = FALSE;
427 // Ensure this only gets run once.
428 if ($finished) {
429 return;
430 }
431
432 views_include('handlers');
433 views_include('cache');
434 views_include('plugins');
435 _views_include_handlers();
436 $finished = TRUE;
437 }
438
439 /**
440 * Load default views files on behalf of modules.
441 */
442 function views_include_default_views() {
443 static $finished = FALSE;
444 // Ensure this only gets run once.
445 if ($finished) {
446 return;
447 }
448
449 // Default views hooks may be in the normal handler file,
450 // or in a separate views_default file at the discretion of
451 // the module author.
452 views_include_handlers();
453
454 _views_include_default_views();
455 $finished = TRUE;
456 }
457
458 // -----------------------------------------------------------------------
459 // Views handler functions
460
461 /**
462 * Fetch a handler from the data cache.
463 */
464 function views_get_handler($table, $field, $key) {
465 $data = views_fetch_data($table);
466 if (isset($data[$field][$key])) {
467 return _views_prepare_handler($data[$field][$key], $data, $field);
468 }
469 // DEBUG -- identify missing handlers
470 vpr("Missing handler: $table $field $key");
471 }
472
473 /**
474 * Fetch Views' data from the cache
475 */
476 function views_fetch_data($table = NULL) {
477 views_include('cache');
478 return _views_fetch_data($table);
479 }
480
481 // -----------------------------------------------------------------------
482 // Views plugin functions
483
484 /**
485 * Fetch the plugin data from cache.
486 */
487 function views_fetch_plugin_data($type = NULL, $plugin = NULL) {
488 views_include('cache');
489 return _views_fetch_plugin_data($type, $plugin);
490 }
491
492 /**
493 * Get a handler for a plugin
494 */
495 function views_get_plugin($type, $plugin) {
496 $definition = views_fetch_plugin_data($type, $plugin);
497 if (!empty($definition)) {
498 return _views_create_handler($definition);
499 }
500 }
501
502 // -----------------------------------------------------------------------
503 // Views database functions
504
505 /**
506 * Get a view from the default views defined by modules.
507 *
508 * Default views are cached per-language. This function will rescan the
509 * default_views hook if necessary.
510 *
511 * @param $view_name
512 * The name of the view to load.
513 * @return
514 * A view object or NULL if it is not available.
515 */
516 function &views_get_default_view($view_name) {
517 $null = NULL;
518 $cache = views_discover_default_views();
519
520 if (isset($cache[$view_name])) {
521 return $cache[$view_name];
522 }
523 return $null;
524 }
525
526 /**
527 * Create an empty view to work with.
528 *
529 * @return
530 * A fully formed, empty $view object. This object must be populated before
531 * it can be successfully saved.
532 */
533 function views_new_view() {
534 views_include('view');
535 $view = new view();
536 $view->vid = 'new';
537 $view->add_display('default');
538
539 return $view;
540 }
541
542 /**
543 * Scan all modules for default views and rebuild the default views cache.
544 *
545 * @return An associative array of all known default views.
546 */
547 function views_discover_default_views() {
548 static $cache = array();
549
550 if (empty($cache)) {
551 views_include('cache');
552 $cache = _views_discover_default_views();
553 }
554 return $cache;
555 }
556
557 /**
558 * Return a list of all views and display IDs that have a particular
559 * setting in their display's plugin settings.
560 *
561 * @return
562 * @code
563 * array(
564 * array($view, $display_id),
565 * array($view, $display_id),
566 * );
567 * @endcode
568 */
569 function views_get_applicable_views($type) {
570 // @todo: Use a smarter flagging system so that we don't have to
571 // load every view for this.
572 $result = array();
573 $views = views_get_all_views();
574
575 foreach ($views as $view) {
576 // Skip disabled views.
577 if (!empty($view->disabled)) {
578 continue;
579 }
580
581 if (empty($view->display)) {
582 // Skip this view as it is broken.
583 vsm(t("Skipping broken view @view", array('@view' => $view->name)));
584 continue;
585 }
586
587 // Loop on array keys because something seems to muck with $view->display
588 // a bit in PHP4.
589 foreach (array_keys($view->display) as $id) {
590 $plugin = views_fetch_plugin_data('display', $view->display[$id]->display_plugin);
591 if (!empty($plugin[$type])) {
592 // This view uses hook menu. Clone it so that different handlers
593 // don't trip over each other, and add it to the list.
594 $v = $view->clone_view();
595 if ($v->set_display($id)) {
596 $result[] = array($v, $id);
597 }
598 // In PHP 4.4.7 and presumably earlier, if we do not unset $v
599 // here, we will find that it actually overwrites references
600 // possibly due to shallow copying issues.
601 unset($v);
602 }
603 }
604 }
605 return $result;
606 }
607
608 /**
609 * Return an array of all views as fully loaded $view objects.
610 */
611 function views_get_all_views() {
612 static $views = array();
613
614 if (empty($views)) {
615 // First, get all applicable views.
616 views_include('view');
617 $views = view::load_views();
618
619 // Get all default views.
620 $status = variable_get('views_defaults', array());
621
622 foreach (views_discover_default_views() as $view) {
623 // Determine if default view is enabled or disabled.
624 if (isset($status[$view->name])) {
625 $view->disabled = $status[$view->name];
626 }
627
628 // If overridden, also say so.
629 if (!empty($views[$view->name])) {
630 $views[$view->name]->type = t('Overridden');
631 }
632 else {
633 $view->type = t('Default');
634 $views[$view->name] = $view;
635 }
636 }
637
638 }
639 return $views;
640 }
641
642 /**
643 * Get a view from the database or from default views.
644 *
645 * This function is just a static wrapper around views::load(). This function
646 * isn't called 'views_load()' primarily because it might get a view
647 * from the default views which aren't technically loaded from the database.
648 *
649 * @param $name
650 * The name of the view.
651 * @param $reset
652 * If TRUE, reset this entry in the load cache.
653 * @return $view
654 * A reference to the $view object. Use $reset if you're sure you want
655 * a fresh one.
656 */
657 function views_get_view($name, $reset = FALSE) {
658 views_include('view');
659 $view = view::load($name, $reset);
660 $default_view = views_get_default_view($name);
661
662 if (empty($view) && empty($default_view)) {
663 return;
664 }
665 elseif (empty($view) && !empty($default_view)) {
666 $default_view->type = t('Default');
667 return $default_view->clone_view();
668 }
669 elseif (!empty($view) && !empty($default_view)) {
670 $view->type = t('Overridden');
671 }
672
673 return $view->clone_view();
674 }
675
676 /**
677 * Basic definition for many views objects
678 */
679 class views_object {
680 /**
681 * Views handlers use a special construct function so that we can more
682 * easily construct them with variable arguments.
683 */
684 function construct() { }
685
686 /**
687 * Let the handler know what its full definition is.
688 */
689 function set_definition($definition) {
690 $this->definition = $definition;
691 if (isset($definition['field'])) {
692 $this->real_field = $definition['field'];
693 }
694 }
695 }
696
697 // ------------------------------------------------------------------
698 // Views debug helper functions
699
700 /**
701 * Provide debug output for Views. This relies on devel.module
702 */
703 function views_debug($message) {
704 if (module_exists('devel') && variable_get('views_devel_output', FALSE)) {
705 drupal_set_content(variable_get('views_devel_region', 'footer'), dpr($message, TRUE));
706 }
707 }
708
709 /**
710 * Shortcut to views_debug()
711 */
712 function vpr($message) {
713 views_debug($message);
714 }
715
716 /**
717 * Debug messages
718 */
719 function vsm($message) {
720 if (module_exists('devel')) {
721 dsm($message);
722 }
723 }
724
725 function views_trace() {
726 $message = '';
727 foreach (debug_backtrace() as $item) {
728 if (!empty($item['file']) && !in_array($item['function'], array('vsm_trace', 'vpr_trace', 'views_trace'))) {
729 $message .= basename($item['file']) . ": " . (empty($item['class']) ? '' : ($item['class'] . '->')) . "$item[function] line $item[line]" . "\n";
730 }
731 }
732 return $message;
733 }
734
735 function vsm_trace() {
736 vsm(views_trace());
737 }
738
739 function vpr_trace() {
740 dpr(views_trace());
741 }
742
743 // ------------------------------------------------------------------
744 // Exposed widgets form
745
746 /**
747 * Form builder for the exposed widgets form.
748 *
749 * Be sure that $view and $display are references.
750 */
751 function views_exposed_form(&$form_state) {
752 $view = &$form_state['view'];
753 $display = &$form_state['display'];
754 // Fill our input either from $_GET or from something previously set on the
755 // view.
756 if (empty($view->exposed_input)) {
757 $input = $_GET;
758 // unset items that are definitely not our input:
759 unset($input['page']);
760 unset($input['q']);
761 // If we have no input at all, check for remembered input via session.
762 if (empty($input) && !empty($_SESSION['views'][$view->name][$view->current_display])) {
763 $input = $_SESSION['views'][$view->name][$view->current_display];
764 }
765 $form['#post'] = $input;
766 }
767 else {
768 $form['#post'] = $view->exposed_input;
769 }
770
771 // Let form plugins know this is for exposed widgets.
772 $form_state['exposed'] = TRUE;
773
774 $form['#info'] = array();
775
776 if (!variable_get('clean_url', FALSE)) {
777 $form['q'] = array(
778 '#type' => 'hidden',
779 '#value' => $view->get_url(),
780 );
781 }
782
783 // Go through each filter and let it generate its info.
784 foreach ($view->filter as $id => $filter) {
785 $filter['handler']->exposed_form($form, $form_state);
786 if ($info = $filter['handler']->exposed_info()) {
787 $form['#info']['filter-' . $id] = $info;
788 }
789 }
790
791 // @todo deal with exposed sorts
792
793 $form['submit'] = array(
794 '#name' => '', // prevent from showing up in $_GET.
795 '#type' => 'submit',
796 '#value' => t('Apply'),
797 );
798
799 $form['#action'] = url($view->get_url());
800 $form['#theme'] = views_theme_functions('views_exposed_form', $view, $display);
801
802 // If using AJAX, we need the form plugin.
803 if ($view->use_ajax) {
804 drupal_add_js('misc/jquery.form.js');
805 }
806 views_add_js('dependent');
807 return $form;
808 }
809
810 /**
811 * Validate handler for exposed filters
812 */
813 function views_exposed_form_validate(&$form, &$form_state) {
814 foreach (array('field', 'filter') as $type) {
815 $var = &$form_state['view']->$type;
816 foreach ($var as $key => $info) {
817 $var[$key]['handler']->exposed_validate($form, $form_state);
818 }
819 }
820 }
821
822 /**
823 * Submit handler for exposed filters
824 */
825 function views_exposed_form_submit(&$form, &$form_state) {
826 foreach (array('field', 'filter') as $type) {
827 $var = &$form_state['view']->$type;
828 foreach ($var as $key => $info) {
829 $var[$key]['handler']->exposed_submit($form, $form_state);
830 }
831 }
832 $form_state['view']->exposed_data = $form_state['values'];
833 $form_state['view']->exposed_raw_input = array();
834
835 foreach ($form_state['values'] as $key => $value) {
836 if (!in_array($key, array('q', 'submit', 'form_build_id', 'form_id', 'form_token'))) {
837 $form_state['view']->exposed_raw_input[$key] = $value;
838 }
839 }
840 }
841
842 // ------------------------------------------------------------------
843 // Misc helpers
844
845 /**
846 * Build a list of theme function names for use most everywhere.
847 */
848 function views_theme_functions($hook, $view, $display = NULL) {
849 require_once './' . drupal_get_path('module', 'views') . "/theme/theme.inc";
850 return _views_theme_functions($hook, $view, $display);
851 }
852
853 /**
854 * Views' replacement for drupal_get_form so that we can do more with
855 * less.
856 *
857 * Items that can be set on the form_state include:
858 * - input: The source of input. If unset this will be $_POST.
859 * - no_redirect: Absolutely do not redirect the form even if instructed
860 * to do so.
861 * - rerender: If no_redirect is set and the form was successfully submitted,
862 * rerender the form. Otherwise it will just return.
863 *
864 */
865 function drupal_build_form($form_id, &$form_state) {
866 views_include('form');
867 return _drupal_build_form($form_id, $form_state);
868 }
869
870 /**
871 * Substitute current time; this works with cached queries.
872 */
873 function views_views_query_substitutions($view) {
874 global $language;
875 return array(
876 '***CURRENT_TIME***' => time(),
877 '***CURRENT_LANGUAGE***' => $language->language,
878 '***NO_LANGUAGE***' => '',
879 );
880 }
881
882 /**
883 * Embed a view using a PHP snippet.
884 *
885 * This function is meant to be called from PHP snippets, should one wish to
886 * embed a view in a node or something. It's meant to provide the simplest
887 * solution and doesn't really offer a lot of options, but breaking the function
888 * apart is pretty easy, and this provides a worthwhile guide to doing so.
889 *
890 * @param $name
891 * The name of the view to embed.
892 * @param $display_id
893 * The display id to embed. If unsure, use 'default', as it will always be
894 * valid. But things like 'page' or 'block' should work here.
895 * @param ...
896 * Any additional parameters will be passed as arguments.
897 */
898 function views_embed_view($name, $display_id = 'default') {
899 $args = func_get_args();
900 array_shift($args); // remove $name
901 if (count($args)) {
902 array_shift($args); // remove $display_id
903 }
904
905 $view = views_get_view($name);
906 if (!$view) {
907 return;
908 }
909
910 return $view->preview($display_id, $args);
911 }
912
913 /**
914 * Export a field.
915 */
916 function views_var_export($var, $prefix = '') {
917 if (is_array($var)) {
918 if (empty($var)) {
919 $output = 'array()';
920 }
921 else {
922 $output = "array(\n";
923 foreach ($var as $key => $value) {
924 $output .= " '$key' => " . views_var_export($value, ' ') . ",\n";
925 }
926 $output .= ')';
927 }
928 }
929 else if (is_bool($var)) {
930 $output = $var ? 'TRUE' : 'FALSE';
931 }
932 else {
933 $output = var_export($var, TRUE);
934 }
935
936 if ($prefix) {
937 $output = str_replace("\n", "\n$prefix", $output);
938 }
939
940 return $output;
941 }
942
943 /**
944 * Prepare the specified string for use as a CSS identifier.
945 */
946 function views_css_safe($string) {
947 return str_replace('_', '-', $string);
948 }