• Main Page
  • Related Pages
  • Modules
  • Classes
  • Files
  • File List
  • File Members

views.module

Go to the documentation of this file.
00001 <?php
00014 function views_api_version() {
00015   return '3.0';
00016 }
00017 
00026 function views_forms($form_id, $args) {
00027   if (strpos($form_id, 'views_form_') === 0) {
00028     return array(
00029       $form_id => array(
00030         'callback' => 'views_form',
00031       ),
00032     );
00033   }
00034 }
00035 
00039 function views_form_id($view) {
00040   $parts = array(
00041     'views_form',
00042     $view->name,
00043     $view->current_display,
00044   );
00045 
00046   return implode('_', $parts);
00047 }
00048 
00052 function views_api_minimum_version() {
00053   return '2';
00054 }
00055 
00059 function views_theme($existing, $type, $theme, $path) {
00060   $path = drupal_get_path('module', 'views');
00061   ctools_include('theme', 'views', 'theme');
00062 
00063   // Some quasi clever array merging here.
00064   $base = array(
00065     'file' => 'theme.inc',
00066     'path' => $path . '/theme',
00067   );
00068 
00069   // Our extra version of pager from pager.inc
00070   $hooks['views_mini_pager'] = $base + array(
00071     'variables' => array('tags' => array(), 'quantity' => 10, 'element' => 0, 'parameters' => array()),
00072     'pattern' => 'views_mini_pager__',
00073   );
00074 
00075   $variables = array(
00076     // For displays, we pass in a dummy array as the first parameter, since
00077     // $view is an object but the core contextual_preprocess() function only
00078     // attaches contextual links when the primary theme argument is an array.
00079     'display' => array('view_array' => array(), 'view' => NULL),
00080     'style' => array('view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL),
00081     'row' => array('view' => NULL, 'options' => NULL, 'row' => NULL, 'field_alias' => NULL),
00082     'exposed_form' => array('view' => NULL, 'options' => NULL),
00083     'pager' => array(
00084       'view' => NULL, 'options' => NULL,
00085       'tags' => array(), 'quantity' => 10, 'element' => 0, 'parameters' => array()
00086     ),
00087   );
00088 
00089   // Default view themes
00090   $hooks['views_view_field'] = $base + array(
00091     'pattern' => 'views_view_field__',
00092     'variables' => array('view' => NULL, 'field' => NULL, 'row' => NULL),
00093   );
00094   $hooks['views_view_grouping'] = $base + array(
00095     'pattern' => 'views_view_grouping__',
00096     'variables' => array('view' => NULL, 'grouping' => NULL, 'grouping_level' => NULL, 'rows' => NULL, 'title' => NULL),
00097   );
00098 
00099   $plugins = views_fetch_plugin_data();
00100 
00101   // Register theme functions for all style plugins
00102   foreach ($plugins as $type => $info) {
00103     foreach ($info as $plugin => $def) {
00104       if (isset($def['theme']) && (!isset($def['register theme']) || !empty($def['register theme']))) {
00105         $hooks[$def['theme']] = array(
00106           'pattern' => $def['theme'] . '__',
00107           'file' => $def['theme file'],
00108           'path' => $def['theme path'],
00109           'variables' => $variables[$type],
00110         );
00111 
00112         $include = DRUPAL_ROOT . '/' . $def['theme path'] . '/' . $def['theme file'];
00113         if (file_exists($include)) {
00114           require_once $include;
00115         }
00116 
00117         if (!function_exists('theme_' . $def['theme'])) {
00118           $hooks[$def['theme']]['template'] = drupal_clean_css_identifier($def['theme']);
00119         }
00120       }
00121       if (isset($def['additional themes'])) {
00122         foreach ($def['additional themes'] as $theme => $theme_type) {
00123           if (empty($theme_type)) {
00124             $theme = $theme_type;
00125             $theme_type = $type;
00126           }
00127 
00128           $hooks[$theme] = array(
00129             'pattern' => $theme . '__',
00130             'file' => $def['theme file'],
00131             'path' => $def['theme path'],
00132             'variables' => $variables[$theme_type],
00133           );
00134 
00135           if (!function_exists('theme_' . $theme)) {
00136             $hooks[$theme]['template'] = drupal_clean_css_identifier($theme);
00137           }
00138         }
00139       }
00140     }
00141   }
00142 
00143   $hooks['views_form_views_form'] = $base + array(
00144     'render element' => 'form',
00145   );
00146 
00147   $hooks['views_exposed_form'] = $base + array(
00148     'template' => 'views-exposed-form',
00149     'pattern' => 'views_exposed_form__',
00150     'render element' => 'form',
00151   );
00152 
00153   $hooks['views_more'] = $base + array(
00154     'template' => 'views-more',
00155     'pattern' => 'views_more__',
00156     'variables' => array('more_url' => NULL, 'link_text' => 'more', 'view' => NULL),
00157   );
00158 
00159   // Add theme suggestions which are part of modules.
00160   foreach (views_get_module_apis() as $info) {
00161     if (isset($info['template path'])) {
00162       $hooks += _views_find_module_templates($hooks, $info['template path']);
00163     }
00164   }
00165   return $hooks;
00166 }
00167 
00178 function _views_find_module_templates($cache, $path) {
00179   $templates = array();
00180   $regex = '/' . '\.tpl\.php' . '$' . '/';
00181 
00182   // Because drupal_system_listing works the way it does, we check for real
00183   // templates separately from checking for patterns.
00184   $files = drupal_system_listing($regex, $path, 'name', 0);
00185   foreach ($files as $template => $file) {
00186     // Chop off the remaining extensions if there are any. $template already
00187     // has the rightmost extension removed, but there might still be more,
00188     // such as with .tpl.php, which still has .tpl in $template at this point.
00189     if (($pos = strpos($template, '.')) !== FALSE) {
00190       $template = substr($template, 0, $pos);
00191     }
00192     // Transform - in filenames to _ to match function naming scheme
00193     // for the purposes of searching.
00194     $hook = strtr($template, '-', '_');
00195     if (isset($cache[$hook])) {
00196       $templates[$hook] = array(
00197         'template' => $template,
00198         'path' => dirname($file->filename),
00199         'includes' => isset($cache[$hook]['includes']) ? $cache[$hook]['includes'] : NULL,
00200       );
00201     }
00202     // Ensure that the pattern is maintained from base themes to its sub-themes.
00203     // Each sub-theme will have their templates scanned so the pattern must be
00204     // held for subsequent runs.
00205     if (isset($cache[$hook]['pattern'])) {
00206       $templates[$hook]['pattern'] = $cache[$hook]['pattern'];
00207     }
00208   }
00209 
00210   $patterns = array_keys($files);
00211 
00212   foreach ($cache as $hook => $info) {
00213     if (!empty($info['pattern'])) {
00214       // Transform _ in pattern to - to match file naming scheme
00215       // for the purposes of searching.
00216       $pattern = strtr($info['pattern'], '_', '-');
00217 
00218       $matches = preg_grep('/^'. $pattern .'/', $patterns);
00219       if ($matches) {
00220         foreach ($matches as $match) {
00221           $file = substr($match, 0, strpos($match, '.'));
00222           // Put the underscores back in for the hook name and register this pattern.
00223           $templates[strtr($file, '-', '_')] = array(
00224             'template' => $file,
00225             'path' => dirname($files[$match]->uri),
00226             'variables' => isset($info['variables']) ? $info['variables'] : NULL,
00227             'render element' => isset($info['render element']) ? $info['render element'] : NULL,
00228             'base hook' => $hook,
00229             'includes' => isset($info['includes']) ? $info['includes'] : NULL,
00230           );
00231         }
00232       }
00233     }
00234   }
00235 
00236   return $templates;
00237 }
00238 
00247 function views_preprocess_node(&$vars) {
00248   // The 'view' attribute of the node is added in views_preprocess_node()
00249   if (!empty($vars['node']->view) && !empty($vars['node']->view->name)) {
00250     $vars['view'] = $vars['node']->view;
00251     $vars['theme_hook_suggestions'][] = 'node__view__' . $vars['node']->view->name;
00252     if (!empty($vars['node']->view->current_display)) {
00253       $vars['theme_hook_suggestions'][] = 'node__view__' . $vars['node']->view->name . '__' . $vars['node']->view->current_display;
00254 
00255       // If a node is being rendered in a view, and the view does not have a path,
00256       // prevent drupal from accidentally setting the $page variable:
00257       if ($vars['page'] && $vars['view_mode'] == 'full' && !$vars['view']->display_handler->has_path()) {
00258         $vars['page'] = FALSE;
00259       }
00260     }
00261   }
00262 
00263   // Allow to alter comments and links based on the settings in the row plugin.
00264   if (!empty($vars['view']->style_plugin->row_plugin) && get_class($vars['view']->style_plugin->row_plugin) == 'views_plugin_row_node_view') {
00265     node_row_node_view_preprocess_node($vars);
00266   }
00267 }
00268 
00273 function views_preprocess_comment(&$vars) {
00274   // The 'view' attribute of the node is added in template_preprocess_views_view_row_comment()
00275   if (!empty($vars['node']->view) && !empty($vars['node']->view->name)) {
00276     $vars['view'] = &$vars['node']->view;
00277     $vars['theme_hook_suggestions'][] = 'comment__view__' . $vars['node']->view->name;
00278     if (!empty($vars['node']->view->current_display)) {
00279       $vars['theme_hook_suggestions'][] = 'comment__view__' . $vars['node']->view->name . '__' . $vars['node']->view->current_display;
00280     }
00281   }
00282 }
00283 
00284 /*
00285  * Implement hook_permission().
00286  */
00287 function views_permission() {
00288   return array(
00289     'administer views' => array(
00290       'title' => t('Administer views'),
00291       'description' => t('Access the views administration pages.'),
00292     ),
00293     'access all views' => array(
00294       'title' => t('Bypass views access control'),
00295       'description' => t('Bypass access control when accessing views.'),
00296     ),
00297   );
00298 }
00299 
00303 function views_menu() {
00304   // Any event which causes a menu_rebuild could potentially mean that the
00305   // Views data is updated -- module changes, profile changes, etc.
00306   views_invalidate_cache();
00307   $items = array();
00308   $items['views/ajax'] = array(
00309     'title' => 'Views',
00310     'page callback' => 'views_ajax',
00311     'theme callback' => 'ajax_base_page_theme',
00312     'delivery callback' => 'ajax_deliver',
00313     'access callback' => TRUE,
00314     'description' => 'Ajax callback for view loading.',
00315     'type' => MENU_CALLBACK,
00316     'file' => 'includes/ajax.inc',
00317   );
00318   // Path is not admin/structure/views due to menu complications with the wildcards from
00319   // the generic ajax callback.
00320   $items['admin/views/ajax/autocomplete/user'] = array(
00321     'page callback' => 'views_ajax_autocomplete_user',
00322     'theme callback' => 'ajax_base_page_theme',
00323     'access callback' => 'user_access',
00324     'access arguments' => array('access content'),
00325     'type' => MENU_CALLBACK,
00326     'file' => 'includes/ajax.inc',
00327   );
00328   // Define another taxonomy autocomplete because the default one of drupal
00329   // does not support a vid a argument anymore
00330   $items['admin/views/ajax/autocomplete/taxonomy'] = array(
00331     'page callback' => 'views_ajax_autocomplete_taxonomy',
00332     'theme callback' => 'ajax_base_page_theme',
00333     'access callback' => 'user_access',
00334     'access arguments' => array('access content'),
00335     'type' => MENU_CALLBACK,
00336     'file' => 'includes/ajax.inc',
00337   );
00338   return $items;
00339 }
00340 
00344 function views_menu_alter(&$callbacks) {
00345   $our_paths = array();
00346   $views = views_get_applicable_views('uses hook menu');
00347   foreach ($views as $data) {
00348     list($view, $display_id) = $data;
00349     $result = $view->execute_hook_menu($display_id, $callbacks);
00350     if (is_array($result)) {
00351       // The menu system doesn't support having two otherwise
00352       // identical paths with different placeholders.  So we
00353       // want to remove the existing items from the menu whose
00354       // paths would conflict with ours.
00355 
00356       // First, we must find any existing menu items that may
00357       // conflict.  We use a regular expression because we don't
00358       // know what placeholders they might use.  Note that we
00359       // first construct the regex itself by replacing %views_arg
00360       // in the display path, then we use this constructed regex
00361       // (which will be something like '#^(foo/%[^/]*/bar)$#') to
00362       // search through the existing paths.
00363       $regex = '#^(' . preg_replace('#%views_arg#', '%[^/]*', implode('|', array_keys($result))) . ')$#';
00364       $matches = preg_grep($regex, array_keys($callbacks));
00365 
00366       // Remove any conflicting items that were found.
00367       foreach ($matches as $path) {
00368         // Don't remove the paths we just added!
00369         if (!isset($our_paths[$path])) {
00370           unset($callbacks[$path]);
00371         }
00372       }
00373       foreach ($result as $path => $item) {
00374         if (!isset($callbacks[$path])) {
00375           // Add a new item, possibly replacing (and thus effectively
00376           // overriding) one that we removed above.
00377           $callbacks[$path] = $item;
00378         }
00379         else {
00380           // This item already exists, so it must be one that we added.
00381           // We change the various callback arguments to pass an array
00382           // of possible display IDs instead of a single ID.
00383           $callbacks[$path]['page arguments'][1] = (array)$callbacks[$path]['page arguments'][1];
00384           $callbacks[$path]['page arguments'][1][] = $display_id;
00385           $callbacks[$path]['access arguments'][] = $item['access arguments'][0];
00386           $callbacks[$path]['load arguments'][1] = (array)$callbacks[$path]['load arguments'][1];
00387           $callbacks[$path]['load arguments'][1][] = $display_id;
00388         }
00389         $our_paths[$path] = TRUE;
00390       }
00391     }
00392   }
00393 
00394   // Save memory: Destroy those views.
00395   foreach ($views as $data) {
00396     list($view, $display_id) = $data;
00397     $view->destroy();
00398   }
00399 }
00400 
00416 function views_arg_load($value, $name, $display_id, $index) {
00417   static $views = array();
00418 
00419   // Make sure we haven't already loaded this views argument for a similar menu
00420   // item elsewhere.
00421   $key = $name . ':' . $display_id . ':' . $value . ':' . $index;
00422   if (isset($views[$key])) {
00423     return $views[$key];
00424   }
00425 
00426   if ($view = views_get_view($name)) {
00427     $view->set_display($display_id);
00428     $view->init_handlers();
00429 
00430     $ids = array_keys($view->argument);
00431 
00432     $indexes = array();
00433     $path = explode('/', $view->get_path());
00434 
00435     foreach ($path as $id => $piece) {
00436       if ($piece == '%' && !empty($ids)) {
00437         $indexes[$id] = array_shift($ids);
00438       }
00439     }
00440 
00441     if (isset($indexes[$index])) {
00442       if (isset($view->argument[$indexes[$index]])) {
00443         $arg = $view->argument[$indexes[$index]]->validate_argument($value) ? $value : FALSE;
00444         $view->destroy();
00445 
00446         // Store the output in case we load this same menu item again.
00447         $views[$key] = $arg;
00448         return $arg;
00449       }
00450     }
00451     $view->destroy();
00452   }
00453 }
00454 
00459 function views_page() {
00460   $args = func_get_args();
00461   $name = array_shift($args);
00462   $display_id = array_shift($args);
00463 
00464   // Load the view and render it.
00465   if ($view = views_get_view($name)) {
00466     return $view->execute_display($display_id, $args);
00467   }
00468 
00469   // Fallback; if we get here no view was found or handler was not valid.
00470   return drupal_not_found();
00471 }
00472 
00476 function views_page_alter(&$page) {
00477   // If the main content of this page contains a view, attach its contextual
00478   // links to the overall page array. This allows them to be rendered directly
00479   // next to the page title.
00480   $view = views_get_page_view();
00481   if (!empty($view)) {
00482     // If a module is still putting in the display like we used to, catch that.
00483     if (is_subclass_of($view, 'views_plugin_display')) {
00484       $view = $view->view;
00485     }
00486 
00487     views_add_contextual_links($page, 'page', $view, $view->current_display);
00488   }
00489 }
00490 
00494 function views_preprocess_html(&$variables) {
00495   // If the page contains a view as its main content, contextual links may have
00496   // been attached to the page as a whole; for example, by views_page_alter().
00497   // This allows them to be associated with the page and rendered by default
00498   // next to the page title (which we want). However, it also causes the
00499   // Contextual Links module to treat the wrapper for the entire page (i.e.,
00500   // the <body> tag) as the HTML element that these contextual links are
00501   // associated with. This we don't want; for better visual highlighting, we
00502   // prefer a smaller region to be chosen. The region we prefer differs from
00503   // theme to theme and depends on the details of the theme's markup in
00504   // page.tpl.php, so we can only find it using JavaScript. We therefore remove
00505   // the "contextual-links-region" class from the <body> tag here and add
00506   // JavaScript that will insert it back in the correct place.
00507   if (!empty($variables['page']['#views_contextual_links_info'])) {
00508     $key = array_search('contextual-links-region', $variables['classes_array']);
00509     if ($key !== FALSE) {
00510       unset($variables['classes_array'][$key]);
00511       // Add the JavaScript, with a group and weight such that it will run
00512       // before modules/contextual/contextual.js.
00513       drupal_add_js(drupal_get_path('module', 'views') . '/js/views-contextual.js', array('group' => JS_LIBRARY, 'weight' => -1));
00514     }
00515   }
00516 }
00517 
00521 function views_contextual_links_view_alter(&$element, $items) {
00522   // If we are rendering views-related contextual links attached to the overall
00523   // page array, add a class to the list of contextual links. This will be used
00524   // by the JavaScript added in views_preprocess_html().
00525   if (!empty($element['#element']['#views_contextual_links_info']) && !empty($element['#element']['#type']) && $element['#element']['#type'] == 'page') {
00526     $element['#attributes']['class'][] = 'views-contextual-links-page';
00527   }
00528 }
00529 
00533 function views_block_info() {
00534   // Try to avoid instantiating all the views just to get the blocks info.
00535   views_include('cache');
00536   $cache = views_cache_get('views_block_items', TRUE);
00537   if ($cache && is_array($cache->data)) {
00538     return $cache->data;
00539   }
00540 
00541   $items = array();
00542   $views = views_get_all_views();
00543   foreach ($views as $view) {
00544     // disabled views get nothing.
00545     if (!empty($view->disabled)) {
00546       continue;
00547     }
00548 
00549     $view->init_display();
00550     foreach ($view->display as $display_id => $display) {
00551 
00552       if (isset($display->handler) && !empty($display->handler->definition['uses hook block'])) {
00553         $result = $display->handler->execute_hook_block_list();
00554         if (is_array($result)) {
00555           $items = array_merge($items, $result);
00556         }
00557       }
00558 
00559       if (isset($display->handler) && $display->handler->get_option('exposed_block')) {
00560         $result = $display->handler->get_special_blocks();
00561         if (is_array($result)) {
00562           $items = array_merge($items, $result);
00563         }
00564       }
00565     }
00566   }
00567 
00568   // block.module has a delta length limit of 32, but our deltas can
00569   // unfortunately be longer because view names can be 32 and display IDs
00570   // can also be 32. So for very long deltas, change to md5 hashes.
00571   $hashes = array();
00572 
00573   // get the keys because we're modifying the array and we don't want to
00574   // confuse PHP too much.
00575   $keys = array_keys($items);
00576   foreach ($keys as $delta) {
00577     if (strlen($delta) >= 32) {
00578       $hash = md5($delta);
00579       $hashes[$hash] = $delta;
00580       $items[$hash] = $items[$delta];
00581       unset($items[$delta]);
00582     }
00583   }
00584 
00585   // Only save hashes if they have changed.
00586   $old_hashes = variable_get('views_block_hashes', array());
00587   if ($hashes != $old_hashes) {
00588     variable_set('views_block_hashes', $hashes);
00589   }
00590   // Save memory: Destroy those views.
00591   foreach ($views as $view) {
00592     $view->destroy();
00593   }
00594 
00595   views_cache_set('views_block_items', $items, TRUE);
00596 
00597   return $items;
00598 }
00599 
00603 function views_block_view($delta) {
00604   $start = microtime(TRUE);
00605   // if this is 32, this should be an md5 hash.
00606   if (strlen($delta) == 32) {
00607     $hashes = variable_get('views_block_hashes', array());
00608     if (!empty($hashes[$delta])) {
00609       $delta = $hashes[$delta];
00610     }
00611   }
00612 
00613   // This indicates it's a special one.
00614   if (substr($delta, 0, 1) == '-') {
00615     list($nothing, $type, $name, $display_id) = explode('-', $delta);
00616     // Put the - back on.
00617     $type = '-' . $type;
00618     if ($view = views_get_view($name)) {
00619       if ($view->access($display_id)) {
00620         $view->set_display($display_id);
00621         if (isset($view->display_handler)) {
00622           $output = $view->display_handler->view_special_blocks($type);
00623           // Before returning the block output, convert it to a renderable
00624           // array with contextual links.
00625           views_add_block_contextual_links($output, $view, $display_id, 'special_block_' . $type);
00626           $view->destroy();
00627           return $output;
00628         }
00629       }
00630       $view->destroy();
00631     }
00632   }
00633 
00634   // If the delta doesn't contain valid data return nothing.
00635   $explode = explode('-', $delta);
00636   if (count($explode) != 2) {
00637     return;
00638   }
00639   list($name, $display_id) = $explode;
00640   // Load the view
00641   if ($view = views_get_view($name)) {
00642     if ($view->access($display_id)) {
00643       $output = $view->execute_display($display_id);
00644       // Before returning the block output, convert it to a renderable array
00645       // with contextual links.
00646       views_add_block_contextual_links($output, $view, $display_id);
00647       $view->destroy();
00648       return $output;
00649     }
00650     $view->destroy();
00651   }
00652 }
00653 
00672 function views_add_block_contextual_links(&$block, $view, $display_id, $block_type = 'block') {
00673   // Do not add contextual links to an empty block.
00674   if (!empty($block['content'])) {
00675     // Contextual links only work on blocks whose content is a renderable
00676     // array, so if the block contains a string of already-rendered markup,
00677     // convert it to an array.
00678     if (is_string($block['content'])) {
00679       $block['content'] = array('#markup' => $block['content']);
00680     }
00681     // Add the contextual links.
00682     views_add_contextual_links($block['content'], $block_type, $view, $display_id);
00683   }
00684 }
00685 
00750 function views_add_contextual_links(&$render_element, $location, $view, $display_id) {
00751   // Do not do anything if the view is configured to hide its administrative
00752   // links.
00753   if (empty($view->hide_admin_links)) {
00754     // Also do not do anything if the display plugin has not defined any
00755     // contextual links that are intended to be displayed in the requested
00756     // location.
00757     $plugin = views_fetch_plugin_data('display', $view->display[$display_id]->display_plugin);
00758     // If contextual links locations are not set, provide a sane default. (To
00759     // avoid displaying any contextual links at all, a display plugin can still
00760     // set 'contextual links locations' to, e.g., an empty array.)
00761     $plugin += array('contextual links locations' => array('view'));
00762     // On exposed_forms blocks contextual links should always be visible.
00763     $plugin['contextual links locations'][] = 'special_block_-exp';
00764     $has_links = !empty($plugin['contextual links']) && !empty($plugin['contextual links locations']);
00765     if ($has_links && in_array($location, $plugin['contextual links locations'])) {
00766       foreach ($plugin['contextual links'] as $module => $link) {
00767         $args = array();
00768         $valid = TRUE;
00769         if (!empty($link['argument properties'])) {
00770           foreach ($link['argument properties'] as $property) {
00771             // If the plugin is trying to create an invalid contextual link
00772             // (for example, "path/to/{$view->property}", where $view->property
00773             // does not exist), we cannot construct the link, so we skip it.
00774             if (!property_exists($view, $property)) {
00775               $valid = FALSE;
00776               break;
00777             }
00778             else {
00779               $args[] = $view->{$property};
00780             }
00781           }
00782         }
00783         // If the link was valid, attach information about it to the renderable
00784         // array.
00785         if ($valid) {
00786           $render_element['#contextual_links'][$module] = array($link['parent path'], $args);
00787           $render_element['#views_contextual_links_info'][$module] = array(
00788             'location' => $location,
00789             'view' => $view,
00790             'view_name' => $view->name,
00791             'view_display_id' => $display_id,
00792           );
00793         }
00794       }
00795     }
00796   }
00797 }
00798 
00812 function views_language_list($field = 'name', $all = FALSE) {
00813   if ($all) {
00814     $languages = language_list();
00815   }
00816   else {
00817     $languages = language_list('enabled');
00818     $languages = $languages[1];
00819   }
00820   $list = array();
00821   foreach ($languages as $language) {
00822     $list[$language->language] = ($field == 'name') ? t($language->name) : $language->$field;
00823   }
00824   return $list;
00825 }
00826 
00830 function views_flush_caches() {
00831   return array('cache_views', 'cache_views_data');
00832 }
00833 
00837 function views_field_create_instance($instance) {
00838   cache_clear_all('*', 'cache_views', TRUE);
00839   cache_clear_all('*', 'cache_views_data', TRUE);
00840 }
00841 
00845 function views_field_update_instance($instance, $prior_instance) {
00846   cache_clear_all('*', 'cache_views', TRUE);
00847   cache_clear_all('*', 'cache_views_data', TRUE);
00848 }
00849 
00853 function views_field_delete_instance($instance) {
00854   cache_clear_all('*', 'cache_views', TRUE);
00855   cache_clear_all('*', 'cache_views_data', TRUE);
00856 }
00857 
00861 function views_invalidate_cache() {
00862   cache_clear_all('*', 'cache_views', TRUE);
00863 }
00864 
00871 function views_import_access() {
00872   return user_access('administer views') && user_access('use PHP for settings');
00873 }
00874 
00884 function views_access() {
00885   $args = func_get_args();
00886   foreach ($args as $arg) {
00887     if ($arg === TRUE) {
00888       return TRUE;
00889     }
00890 
00891     if (!is_array($arg)) {
00892       continue;
00893     }
00894 
00895     list($callback, $arguments) = $arg;
00896     $arguments = $arguments ? $arguments : array();
00897     // Bring dynamic arguments to the access callback.
00898     foreach ($arguments as $key => $value) {
00899       if (is_int($value) && isset($args[$value])) {
00900         $arguments[$key] = $args[$value];
00901       }
00902     }
00903     if (function_exists($callback) && call_user_func_array($callback, $arguments)) {
00904       return TRUE;
00905     }
00906   }
00907 
00908   return FALSE;
00909 }
00910 
00918 function views_check_perm($perm, $account = NULL) {
00919   return user_access($perm, $account) || user_access('access all views', $account);
00920 }
00921 
00929 function views_check_roles($rids, $account = NULL) {
00930   global $user;
00931   $account = isset($account) ? $account : $user;
00932   $roles = array_keys($account->roles);
00933   $roles[] = $account->uid ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID;
00934   return user_access('access all views', $account) || array_intersect(array_filter($rids), $roles);
00935 }
00936 // ------------------------------------------------------------------
00937 // Functions to help identify views that are running or ran
00938 
00943 function &views_set_page_view($view = NULL) {
00944   static $cache = NULL;
00945   if (isset($view)) {
00946     $cache = $view;
00947   }
00948 
00949   return $cache;
00950 }
00951 
00960 function &views_get_page_view() {
00961   return views_set_page_view();
00962 }
00963 
00970 function &views_set_current_view($view = NULL) {
00971   static $cache = NULL;
00972   if (isset($view)) {
00973     $cache = $view;
00974   }
00975 
00976   return $cache;
00977 }
00978 
00986 function &views_get_current_view() {
00987   return views_set_current_view();
00988 }
00989 
00990 // ------------------------------------------------------------------
00991 // Include file helpers
00992 
00996 function views_include($file) {
00997   ctools_include($file, 'views');
00998 }
00999 
01003 function views_module_include($api, $reset = FALSE) {
01004   if ($reset) {
01005     $cache = &drupal_static('ctools_plugin_api_info');
01006     if (isset($cache['views']['views'])) {
01007       unset($cache['views']['views']);
01008     }
01009   }
01010   ctools_include('plugins');
01011   return ctools_plugin_api_include('views', $api, views_api_minimum_version(), views_api_version());
01012 }
01013 
01017 function views_get_module_apis($api = 'views', $reset = FALSE) {
01018   if ($reset) {
01019     $cache = &drupal_static('ctools_plugin_api_info');
01020     if (isset($cache['views']['views'])) {
01021       unset($cache['views']['views']);
01022     }
01023   }
01024   ctools_include('plugins');
01025   return ctools_plugin_api_info('views', $api, views_api_minimum_version(), views_api_version());
01026 }
01027 
01031 function views_add_css($file) {
01032   // We set preprocess to FALSE because we are adding the files conditionally,
01033   // and we don't want to generate duplicate cache files.
01034   // TODO: at some point investigate adding some files unconditionally and
01035   // allowing preprocess.
01036   drupal_add_css(drupal_get_path('module', 'views') . "/css/$file.css", array('preprocess' => FALSE));
01037 }
01038 
01042 function views_add_js($file) {
01043   // If javascript has been disabled by the user, never add js files.
01044   if (variable_get('views_no_javascript', FALSE)) {
01045     return;
01046   }
01047   static $base = TRUE, $ajax = TRUE;
01048   if ($base) {
01049     drupal_add_js(drupal_get_path('module', 'views') . "/js/base.js");
01050     $base = FALSE;
01051   }
01052   if ($ajax && in_array($file, array('ajax', 'ajax_view'))) {
01053     drupal_add_library('system', 'drupal.ajax');
01054     drupal_add_library('system', 'jquery.form');
01055     $ajax = FALSE;
01056   }
01057   ctools_add_js($file, 'views');
01058 }
01059 
01063 function views_include_handlers($reset = FALSE) {
01064   static $finished = FALSE;
01065   // Ensure this only gets run once.
01066   if ($finished && !$reset) {
01067     return;
01068   }
01069 
01070   views_include('base');
01071   views_include('handlers');
01072   views_include('cache');
01073   views_include('plugins');
01074   views_module_include('views', $reset);
01075   $finished = TRUE;
01076 }
01077 
01078 // -----------------------------------------------------------------------
01079 // Views handler functions
01080 
01098 function views_get_handler($table, $field, $key, $override = NULL) {
01099   static $recursion_protection = array();
01100 
01101   $data = views_fetch_data($table, FALSE);
01102   $handler = NULL;
01103   views_include('handlers');
01104 
01105   // Support old views_data entries conversion.
01106 
01107   // Support conversion on table level.
01108   if (isset($data['moved to'])) {
01109     $moved = array($data['moved to'], $field);
01110   }
01111   // Support conversion on datafield level.
01112   if (isset($data[$field]['moved to'])) {
01113     $moved = $data[$field]['moved to'];
01114   }
01115   // Support conversion on handler level.
01116   if (isset($data[$field][$key]['moved to'])) {
01117     $moved = $data[$field][$key]['moved to'];
01118   }
01119 
01120   if (isset($data[$field][$key]) || !empty($moved)) {
01121     if (!empty($moved)) {
01122       list($moved_table, $moved_field) = $moved;
01123       if (!empty($recursion_protection[$moved_table][$moved_field])) {
01124         // recursion detected!
01125         return NULL;
01126       }
01127 
01128       $recursion_protection[$moved_table][$moved_field] = TRUE;
01129       $handler = views_get_handler($moved_table, $moved_field, $key, $override);
01130       $recursion_protection = array();
01131       if ($handler) {
01132         // store these values so we know what we were originally called.
01133         $handler->original_table = $table;
01134         $handler->original_field = $field;
01135         if (empty($handler->actual_table)) {
01136           $handler->actual_table = $moved_table;
01137           $handler->actual_field = $moved_field;
01138         }
01139       }
01140       return $handler;
01141     }
01142 
01143     // Set up a default handler:
01144     if (empty($data[$field][$key]['handler'])) {
01145       $data[$field][$key]['handler'] = 'views_handler_' . $key;
01146     }
01147 
01148     if ($override) {
01149       $data[$field][$key]['override handler'] = $override;
01150     }
01151 
01152     $handler = _views_prepare_handler($data[$field][$key], $data, $field, $key);
01153   }
01154 
01155   if ($handler) {
01156     return $handler;
01157   }
01158 
01159   // DEBUG -- identify missing handlers
01160   vpr("Missing handler: @table @field @key", array('@table' => $table, '@field' => $field, '@key' => $key));
01161   $broken = array(
01162     'title' => t('Broken handler @table.@field', array('@table' => $table, '@field' => $field)),
01163     'handler' => 'views_handler_' . $key . '_broken',
01164     'table' => $table,
01165     'field' => $field,
01166   );
01167   return _views_create_handler($broken, 'handler', $key);
01168 }
01169 
01173 function views_fetch_data($table = NULL, $move = TRUE, $reset = FALSE) {
01174   views_include('cache');
01175   return _views_fetch_data($table, $move, $reset);
01176 }
01177 
01178 // -----------------------------------------------------------------------
01179 // Views plugin functions
01180 
01184 function views_fetch_plugin_data($type = NULL, $plugin = NULL, $reset = FALSE) {
01185   views_include('cache');
01186   return _views_fetch_plugin_data($type, $plugin, $reset);
01187 }
01188 
01203 function views_fetch_plugin_names($type, $key = NULL, $base = array()) {
01204   $data = views_fetch_plugin_data();
01205 
01206   $plugins[$type] = array();
01207 
01208   foreach ($data[$type] as $id => $plugin) {
01209     // Skip plugins that don't conform to our key.
01210     if ($key && (empty($plugin['type']) || $plugin['type'] != $key)) {
01211       continue;
01212     }
01213     if (empty($plugin['no ui']) && (empty($base) || empty($plugin['base']) || array_intersect($base, $plugin['base']))) {
01214       $plugins[$type][$id] = $plugin['title'];
01215     }
01216   }
01217 
01218   if (!empty($plugins[$type])) {
01219     asort($plugins[$type]);
01220     return $plugins[$type];
01221   }
01222   // fall-through
01223   return array();
01224 }
01225 
01233 function views_get_plugin($type, $plugin, $reset = FALSE) {
01234   views_include('handlers');
01235   $definition = views_fetch_plugin_data($type, $plugin, $reset);
01236   if (!empty($definition)) {
01237     return _views_create_handler($definition, $type);
01238   }
01239 }
01240 
01246 function views_get_localization_plugin() {
01247   $plugin = variable_get('views_localization_plugin', '');
01248   // Provide sane default values for the localization plugin.
01249   if (empty($plugin)) {
01250     if (module_exists('locale')) {
01251       $plugin = 'core';
01252     }
01253     else {
01254       $plugin = 'none';
01255     }
01256   }
01257 
01258   return $plugin;
01259 }
01260 
01261 // -----------------------------------------------------------------------
01262 // Views database functions
01263 
01270 function views_get_all_templates() {
01271   $templates = array();
01272   $modules = views_module_include('views_template');
01273 
01274   foreach ($modules as $module => $info) {
01275     $function = $module . '_views_templates';
01276     if (function_exists($function)) {
01277       $new = $function();
01278       if ($new && is_array($new)) {
01279         $templates = array_merge($new, $templates);
01280       }
01281     }
01282   }
01283 
01284   return $templates;
01285 }
01286 
01294 function views_new_view() {
01295   views_include('view');
01296   $view = new view();
01297   $view->vid = 'new';
01298   $view->add_display('default');
01299 
01300   return $view;
01301 }
01302 
01315 function views_get_applicable_views($type) {
01316   // @todo: Use a smarter flagging system so that we don't have to
01317   // load every view for this.
01318   $result = array();
01319   $views = views_get_all_views();
01320 
01321   foreach ($views as $view) {
01322     // Skip disabled views.
01323     if (!empty($view->disabled)) {
01324       continue;
01325     }
01326 
01327     if (empty($view->display)) {
01328       // Skip this view as it is broken.
01329       vsm(t("Skipping broken view @view", array('@view' => $view->name)));
01330       continue;
01331     }
01332 
01333     // Loop on array keys because something seems to muck with $view->display
01334     // a bit in PHP4.
01335     foreach (array_keys($view->display) as $id) {
01336       $plugin = views_fetch_plugin_data('display', $view->display[$id]->display_plugin);
01337       if (!empty($plugin[$type])) {
01338         // This view uses hook menu. Clone it so that different handlers
01339         // don't trip over each other, and add it to the list.
01340         $v = $view->clone_view();
01341         if ($v->set_display($id) && $v->display_handler->get_option('enabled')) {
01342           $result[] = array($v, $id);
01343         }
01344         // In PHP 4.4.7 and presumably earlier, if we do not unset $v
01345         // here, we will find that it actually overwrites references
01346         // possibly due to shallow copying issues.
01347         unset($v);
01348       }
01349     }
01350   }
01351   return $result;
01352 }
01353 
01360 function views_get_all_views($reset = FALSE) {
01361   ctools_include('export');
01362   return ctools_export_crud_load_all('views_view', $reset);
01363 }
01364 
01368 function views_get_enabled_views() {
01369   $views = views_get_all_views();
01370   return array_filter($views, 'views_view_is_enabled');
01371 }
01372 
01376 function views_get_disabled_views() {
01377   $views = views_get_all_views();
01378   return array_filter($views, 'views_view_is_disabled');
01379 }
01380 
01404 function views_get_views_as_options($views_only = FALSE, $filter = 'all', $exclude_view = NULL, $optgroup = FALSE) {
01405 
01406   // Filter the big views array.
01407   switch ($filter) {
01408     case 'all':
01409     case 'disabled':
01410     case 'enabled':
01411       $func = "views_get_{$filter}_views";
01412       $views = $func();
01413       break;
01414     default:
01415       return array();
01416   }
01417 
01418   // Prepare exclude view strings for comparison.
01419   if (empty($exclude_view)) {
01420     $exclude_view_name = '';
01421     $exclude_view_display = '';
01422   }
01423   elseif (is_object($exclude_view)) {
01424     $exclude_view_name = $exclude_view->name;
01425     $exclude_view_display = $exclude_view->current_display;
01426   }
01427   else {
01428     list($exclude_view_name, $exclude_view_display) = explode(':', $exclude_view);
01429   }
01430 
01431   $options = array();
01432   foreach ($views as $view) {
01433     // Return only views.
01434     if ($views_only && $view->name != $exclude_view_name) {
01435       $options[$view->name] = $view->get_human_name();
01436     }
01437     // Return views with display ids.
01438     else {
01439       foreach ($view->display as $display_id => $display) {
01440         if (!($view->name == $exclude_view_name && $display_id == $exclude_view_display)) {
01441           if ($optgroup) {
01442             $options[$view->name][$view->name . ':' . $display->id] = t('@view : @display', array('@view' => $view->name, '@display' => $display->id));
01443           }
01444           else {
01445             $options[$view->name . ':' . $display->id] = t('View: @view - Display: @display', array('@view' => $view->name, '@display' => $display->id));
01446           }
01447         }
01448       }
01449     }
01450   }
01451   return $options;
01452 }
01453 
01457 function views_view_is_enabled($view) {
01458   return empty($view->disabled);
01459 }
01460 
01464 function views_view_is_disabled($view) {
01465   return !empty($view->disabled);
01466 }
01467 
01483 function views_get_view($name, $reset = FALSE) {
01484   if ($reset) {
01485     $cache = &drupal_static('ctools_export_load_object');
01486     if (isset($cache['views_view'][$name])) {
01487       unset($cache['views_view'][$name]);
01488     }
01489   }
01490 
01491   ctools_include('export');
01492   $view = ctools_export_crud_load('views_view', $name);
01493   if ($view) {
01494     $view->update();
01495     return $view->clone_view();
01496   }
01497 }
01498 
01505 function views_move_table($table) {
01506   $data = views_fetch_data($table, FALSE);
01507   if (isset($data['moved to'])) {
01508     $table = $data['moved to'];
01509   }
01510 
01511   return $table;
01512 }
01513 
01517 function views_load_display_records(&$views) {
01518   // Get vids from the views.
01519   $names = array();
01520   foreach ($views as $view) {
01521     if (empty($view->display)) {
01522       $names[$view->vid] = $view->name;
01523     }
01524   }
01525 
01526   if (empty($names)) {
01527     return;
01528   }
01529 
01530   foreach (view::db_objects() as $key) {
01531     $object_name = "views_$key";
01532     $result = db_query("SELECT * FROM {{$object_name}} WHERE vid IN (:vids) ORDER BY vid, position",
01533       array(':vids' => array_keys($names)));
01534 
01535     foreach ($result as $data) {
01536       $object = new $object_name(FALSE);
01537       $object->load_row($data);
01538 
01539       // Because it can get complicated with this much indirection,
01540       // make a shortcut reference.
01541       $location = &$views[$names[$object->vid]]->$key;
01542 
01543       // If we have a basic id field, load the item onto the view based on
01544       // this ID, otherwise push it on.
01545       if (!empty($object->id)) {
01546         $location[$object->id] = $object;
01547       }
01548       else {
01549         $location[] = $object;
01550       }
01551     }
01552   }
01553 }
01554 
01558 function views_save_view(&$view) {
01559   return $view->save();
01560 }
01561 
01565 function views_delete_view(&$view) {
01566   return $view->delete(TRUE);
01567 }
01568 
01572 function views_export_view(&$view, $indent = '') {
01573   return $view->export($indent);
01574 }
01575 
01576 // ------------------------------------------------------------------
01577 // Views debug helper functions
01578 
01594 function views_debug($message, $placeholders = array()) {
01595   if (!is_string($message)) {
01596     $output = '<pre>' . var_export($message, TRUE) . '</pre>';
01597   }
01598   if (module_exists('devel') && variable_get('views_devel_output', FALSE) && user_access('access devel information')) {
01599     $devel_region = variable_get('views_devel_region', 'footer');
01600     if ($devel_region == 'watchdog') {
01601       $output = $message;
01602       watchdog('views_logging', $output, $placeholders);
01603     }
01604     else if ($devel_region == 'drupal_debug') {
01605       $output = empty($output) ? t($message, $placeholders) : $output;
01606       dd($output);
01607     }
01608     else {
01609       $output = empty($output) ? t($message, $placeholders) : $output;
01610       dpm($output);
01611     }
01612   }
01613   elseif (isset($GLOBALS['drupal_test_info'])) {
01614     $output = empty($output) ? t($message, $placeholders) : $output;
01615     debug($output);
01616   }
01617 }
01618 
01622 function vpr($message, $placeholders = array()) {
01623   views_debug($message, $placeholders);
01624 }
01625 
01629 function vsm($message) {
01630   if (module_exists('devel')) {
01631     dpm($message);
01632   }
01633 }
01634 
01635 function views_trace() {
01636   $message = '';
01637   foreach (debug_backtrace() as $item) {
01638     if (!empty($item['file']) && !in_array($item['function'], array('vsm_trace', 'vpr_trace', 'views_trace'))) {
01639       $message .= basename($item['file']) . ": " . (empty($item['class']) ? '' : ($item['class'] . '->')) . "$item[function] line $item[line]" . "\n";
01640     }
01641   }
01642   return $message;
01643 }
01644 
01645 function vsm_trace() {
01646   vsm(views_trace());
01647 }
01648 
01649 function vpr_trace() {
01650   dpr(views_trace());
01651 }
01652 
01653 // ------------------------------------------------------------------
01654 // Views form (View with form elements)
01655 
01660 function views_view_has_form_elements($view) {
01661   foreach ($view->field as $field) {
01662     if (property_exists($field, 'views_form_callback') || method_exists($field, 'views_form')) {
01663       return TRUE;
01664     }
01665   }
01666   $area_handlers = array_merge(array_values($view->header), array_values($view->footer));
01667   $empty = empty($view->result);
01668   foreach ($area_handlers as $area) {
01669     if (method_exists($area, 'views_form') && !$area->views_form_empty($empty)) {
01670       return TRUE;
01671     }
01672   }
01673   return FALSE;
01674 }
01675 
01682 function views_form($form, &$form_state, $view, $output) {
01683   $form_state['step'] = isset($form_state['step']) ? $form_state['step'] : 'views_form_views_form';
01684 
01685   $form = array();
01686   $query = drupal_get_query_parameters($_GET, array('q'));
01687   $form['#action'] = url($view->get_url(), array('query' => $query));
01688   $form['#validate'] = array('views_form_validate');
01689   $form['#submit'] = array('views_form_submit');
01690   // Tell the preprocessor whether it should hide the header, footer, pager...
01691   $form['show_view_elements'] = array(
01692     '#type' => 'value',
01693     '#value' => ($form_state['step'] == 'views_form_views_form') ? TRUE : FALSE,
01694   );
01695 
01696   $form = $form_state['step']($form, $form_state, $view, $output);
01697   return $form;
01698 }
01699 
01704 function views_form_validate($form, &$form_state) {
01705   // Fire the hook. Doesn't use module_invoke_all() because $form_state needs
01706   // to be passed by reference.
01707   foreach (module_implements('views_form_validate') as $module) {
01708     $function = $module . '_views_form_validate';
01709     $function($form, $form_state);
01710   }
01711 }
01712 
01717 function views_form_submit($form, &$form_state) {
01718   // Fire the hook. Doesn't use module_invoke_all() because $form_state needs
01719   // to be passed by reference.
01720   foreach (module_implements('views_form_submit') as $module) {
01721     $function = $module . '_views_form_submit';
01722     $function($form, $form_state);
01723   }
01724 }
01725 
01730 function views_form_views_form($form, &$form_state, $view, $output) {
01731   $form['#prefix'] = '<div class="views-form">';
01732   $form['#suffix'] = '</div>';
01733   $form['#theme'] = 'views_form_views_form';
01734   $form['#validate'][] = 'views_form_views_form_validate';
01735   $form['#submit'][] = 'views_form_views_form_submit';
01736 
01737   // Add the output markup to the form array so that it's included when the form
01738   // array is passed to the theme function.
01739   $form['output'] = array(
01740     '#type' => 'markup',
01741     '#markup' => $output,
01742     // This way any additional form elements will go before the view
01743     // (below the exposed widgets).
01744     '#weight' => 50,
01745   );
01746 
01747   $substitutions = array();
01748   foreach ($view->field as $field_name => $field) {
01749     $form_element_name = $field_name;
01750     if (method_exists($field, 'form_element_name')) {
01751       $form_element_name = $field->form_element_name();
01752     }
01753     $method_form_element_row_id_exists = FALSE;
01754     if (method_exists($field, 'form_element_row_id')) {
01755       $method_form_element_row_id_exists = TRUE;
01756     }
01757 
01758     // If the field provides a views form, allow it to modify the $form array.
01759     $has_form = FALSE;
01760     if (property_exists($field, 'views_form_callback')) {
01761       $callback = $field->views_form_callback;
01762       $callback($view, $field, $form, $form_state);
01763       $has_form = TRUE;
01764     }
01765     elseif (method_exists($field, 'views_form')) {
01766       $field->views_form($form, $form_state);
01767       $has_form = TRUE;
01768     }
01769 
01770     // Build the substitutions array for use in the theme function.
01771     if ($has_form) {
01772       foreach ($view->result as $row_id => $row) {
01773         if ($method_form_element_row_id_exists) {
01774           $form_element_row_id = $field->form_element_row_id($row_id);
01775         }
01776         else {
01777           $form_element_row_id = $row_id;
01778         }
01779 
01780         $substitutions[] = array(
01781           'placeholder' => '<!--form-item-' . $form_element_name . '--' . $form_element_row_id . '-->',
01782           'field_name' => $form_element_name,
01783           'row_id' => $form_element_row_id,
01784         );
01785       }
01786     }
01787   }
01788 
01789   // Give the area handlers a chance to extend the form.
01790   $area_handlers = array_merge(array_values($view->header), array_values($view->footer));
01791   $empty = empty($view->result);
01792   foreach ($area_handlers as $area) {
01793     if (method_exists($area, 'views_form') && !$area->views_form_empty($empty)) {
01794       $area->views_form($form, $form_state);
01795     }
01796   }
01797 
01798   $form['#substitutions'] = array(
01799     '#type' => 'value',
01800     '#value' => $substitutions,
01801   );
01802   $form['actions'] = array(
01803     '#type' => 'container',
01804     '#attributes' => array('class' => array('form-actions')),
01805     '#weight' => 100,
01806   );
01807   $form['actions']['submit'] = array(
01808     '#type' => 'submit',
01809     '#value' => t('Save'),
01810   );
01811 
01812   return $form;
01813 }
01814 
01820 function views_form_views_form_validate($form, &$form_state) {
01821   $view = $form_state['build_info']['args'][0];
01822 
01823   // Call the validation method on every field handler that has it.
01824   foreach ($view->field as $field_name => $field) {
01825     if (method_exists($field, 'views_form_validate')) {
01826       $field->views_form_validate($form, $form_state);
01827     }
01828   }
01829 
01830   // Call the validate method on every area handler that has it.
01831   foreach (array('header', 'footer') as $area) {
01832     foreach ($view->{$area} as $area_name => $area_handler) {
01833       if (method_exists($area_handler, 'views_form_validate')) {
01834         $area_handler->views_form_validate($form, $form_state);
01835       }
01836     }
01837   }
01838 }
01839 
01845 function views_form_views_form_submit($form, &$form_state) {
01846   $view = $form_state['build_info']['args'][0];
01847 
01848   // Call the submit method on every field handler that has it.
01849   foreach ($view->field as $field_name => $field) {
01850     if (method_exists($field, 'views_form_submit')) {
01851       $field->views_form_submit($form, $form_state);
01852     }
01853   }
01854 
01855   // Call the submit method on every area handler that has it.
01856   foreach (array('header', 'footer') as $area) {
01857     foreach ($view->{$area} as $area_name => $area_handler) {
01858       if (method_exists($area_handler, 'views_form_submit')) {
01859         $area_handler->views_form_submit($form, $form_state);
01860       }
01861     }
01862   }
01863 }
01864 
01865 // ------------------------------------------------------------------
01866 // Exposed widgets form
01867 
01873 function views_exposed_form($form, &$form_state) {
01874   // Don't show the form when batch operations are in progress.
01875   if ($batch = batch_get() && isset($batch['current_set'])) {
01876     return array(
01877       // Set the theme callback to be nothing to avoid errors in template_preprocess_views_exposed_form().
01878       '#theme' => '',
01879     );
01880   }
01881 
01882   // Make sure that we validate because this form might be submitted
01883   // multiple times per page.
01884   $form_state['must_validate'] = TRUE;
01885   $view = &$form_state['view'];
01886   $display = &$form_state['display'];
01887 
01888   $form_state['input'] = $view->get_exposed_input();
01889 
01890   // Let form plugins know this is for exposed widgets.
01891   $form_state['exposed'] = TRUE;
01892   // Check if the form was already created
01893   if ($cache = views_exposed_form_cache($view->name, $view->current_display)) {
01894     return $cache;
01895   }
01896 
01897   $form['#info'] = array();
01898 
01899   if (!variable_get('clean_url', FALSE)) {
01900     $form['q'] = array(
01901       '#type' => 'hidden',
01902       '#value' => $view->get_url(),
01903     );
01904   }
01905 
01906   // Go through each handler and let it generate its exposed widget.
01907   foreach ($view->display_handler->handlers as $type => $value) {
01908     foreach ($view->$type as $id => $handler) {
01909       if ($handler->can_expose() && $handler->is_exposed()) {
01910         $handler->exposed_form($form, $form_state);
01911         if ($info = $handler->exposed_info()) {
01912           $form['#info']["$type-$id"] = $info;
01913         }
01914       }
01915     }
01916   }
01917 
01918   $form['submit'] = array(
01919     '#name' => '', // prevent from showing up in $_GET.
01920     '#type' => 'submit',
01921     '#value' => t('Apply'),
01922     '#id' => drupal_html_id('edit-submit-' . $view->name),
01923   );
01924 
01925   $form['#action'] = url($view->get_url());
01926   $form['#theme'] = views_theme_functions('views_exposed_form', $view, $display);
01927   $form['#id'] = drupal_clean_css_identifier('views_exposed_form-' . check_plain($view->name) . '-' . check_plain($display->id));
01928 //  $form['#attributes']['class'] = array('views-exposed-form');
01929 
01930   // If using AJAX, we need the form plugin.
01931   if ($view->use_ajax) {
01932     drupal_add_library('system', 'jquery.form');
01933   }
01934   ctools_include('dependent');
01935 
01936   $exposed_form_plugin = $form_state['exposed_form_plugin'];
01937   $exposed_form_plugin->exposed_form_alter($form, $form_state);
01938 
01939   // Save the form
01940   views_exposed_form_cache($view->name, $view->current_display, $form);
01941 
01942   return $form;
01943 }
01944 
01951 function views_form_views_exposed_form_alter(&$form, &$form_state) {
01952   $form['form_build_id']['#access'] = FALSE;
01953   $form['form_token']['#access'] = FALSE;
01954   $form['form_id']['#access'] = FALSE;
01955 }
01956 
01960 function views_exposed_form_validate(&$form, &$form_state) {
01961   foreach (array('field', 'filter') as $type) {
01962     $handlers = &$form_state['view']->$type;
01963     foreach ($handlers as $key => $handler) {
01964       $handlers[$key]->exposed_validate($form, $form_state);
01965     }
01966   }
01967   $exposed_form_plugin = $form_state['exposed_form_plugin'];
01968   $exposed_form_plugin->exposed_form_validate($form, $form_state);
01969 }
01970 
01974 function views_exposed_form_submit(&$form, &$form_state) {
01975   foreach (array('field', 'filter') as $type) {
01976     $handlers = &$form_state['view']->$type;
01977     foreach ($handlers as $key => $info) {
01978       $handlers[$key]->exposed_submit($form, $form_state);
01979     }
01980   }
01981   $form_state['view']->exposed_data = $form_state['values'];
01982   $form_state['view']->exposed_raw_input = array();
01983 
01984 
01985   $exclude = array('q', 'submit', 'form_build_id', 'form_id', 'form_token', 'exposed_form_plugin', '', 'reset');
01986   $exposed_form_plugin = $form_state['exposed_form_plugin'];
01987   $exposed_form_plugin->exposed_form_submit($form, $form_state, $exclude);
01988 
01989   foreach ($form_state['values'] as $key => $value) {
01990     if (!in_array($key, $exclude)) {
01991       $form_state['view']->exposed_raw_input[$key] = $value;
01992     }
01993   }
01994 }
01995 
02008 function views_exposed_form_cache($views_name, $display_name, $form_output = NULL) {
02009   static $views_exposed;
02010 
02011   // Save the form output
02012   if (!empty($form_output)) {
02013     $views_exposed[$views_name][$display_name] = $form_output;
02014     return;
02015   }
02016 
02017   // Return the form output, if any
02018   return empty($views_exposed[$views_name][$display_name]) ? FALSE : $views_exposed[$views_name][$display_name];
02019 }
02020 
02021 // ------------------------------------------------------------------
02022 // Misc helpers
02023 
02027 function views_theme_functions($hook, $view, $display = NULL) {
02028   require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'views') . "/theme/theme.inc";
02029   return _views_theme_functions($hook, $view, $display);
02030 }
02031 
02035 function views_views_query_substitutions($view) {
02036   global $language_content;
02037   return array(
02038     '***CURRENT_VERSION***' => VERSION,
02039     '***CURRENT_TIME***' => REQUEST_TIME,
02040     '***CURRENT_LANGUAGE***' => $language_content->language,
02041     '***DEFAULT_LANGUAGE***' => language_default('language'),
02042   );
02043 }
02044 
02051 function views_query_views_alter(QueryAlterableInterface $query) {
02052   $substitutions = $query->getMetaData('views_substitutions');
02053   $tables =& $query->getTables();
02054   $where =& $query->conditions();
02055 
02056   // Replaces substitions in tables.
02057   foreach ($tables as $table_name => $table_metadata) {
02058     foreach ($table_metadata['arguments'] as $replacement_key => $value) {
02059       if (isset($substitutions[$value])) {
02060         $tables[$table_name]['arguments'][$replacement_key] = $substitutions[$value];
02061       }
02062     }
02063   }
02064 
02065   // Replaces substitions in filter criterias.
02066   _views_query_tag_alter_condition($query, $where, $substitutions);
02067 }
02068 
02072 function _views_query_tag_alter_condition(QueryAlterableInterface $query, &$conditions, $substitutions) {
02073   foreach ($conditions as $condition_id => &$condition) {
02074     if (is_numeric($condition_id)) {
02075       if (is_string($condition['field'])) {
02076         $condition['field'] = str_replace(array_keys($substitutions), array_values($substitutions), $condition['field']);
02077       }
02078       elseif (is_object($condition['field'])) {
02079         $sub_conditions =& $condition['field']->conditions();
02080         _views_query_tag_alter_condition($query, $sub_conditions, $substitutions);
02081       }
02082       // $condition['value'] is a subquery so alter the subquery recursive.
02083       // Therefore take sure to get the metadata of the main query.
02084       if (is_object($condition['value'])) {
02085         $subquery = $condition['value'];
02086         $subquery->addMetaData('views_substitutions', $query->getMetaData('views_substitutions'));
02087         views_query_views_alter($condition['value']);
02088       }
02089       elseif (isset($condition['value'])) {
02090         $condition['value'] = str_replace(array_keys($substitutions), array_values($substitutions), $condition['value']);
02091       }
02092     }
02093   }
02094 }
02095 
02116 function views_embed_view($name, $display_id = 'default') {
02117   $args = func_get_args();
02118   array_shift($args); // remove $name
02119   if (count($args)) {
02120     array_shift($args); // remove $display_id
02121   }
02122 
02123   $view = views_get_view($name);
02124   if (!$view || !$view->access($display_id)) {
02125     return;
02126   }
02127 
02128   return $view->preview($display_id, $args);
02129 }
02130 
02149 function views_get_view_result($name, $display_id = NULL) {
02150   $args = func_get_args();
02151   array_shift($args); // remove $name
02152   if (count($args)) {
02153     array_shift($args); // remove $display_id
02154   }
02155 
02156   $view = views_get_view($name);
02157   if (is_object($view)) {
02158     if (is_array($args)) {
02159       $view->set_arguments($args);
02160     }
02161     if (is_string($display_id)) {
02162       $view->set_display($display_id);
02163     }
02164     else {
02165       $view->init_display();
02166     }
02167     $view->pre_execute();
02168     $view->execute();
02169     return $view->result;
02170   }
02171   else {
02172     return array();
02173   }
02174 }
02175 
02179 function views_var_export($var, $prefix = '', $init = TRUE) {
02180   if (is_array($var)) {
02181     if (empty($var)) {
02182       $output = 'array()';
02183     }
02184     else {
02185       $output = "array(\n";
02186       foreach ($var as $key => $value) {
02187         $output .= "  " . views_var_export($key, '', FALSE) . " => " . views_var_export($value, '  ', FALSE) . ",\n";
02188       }
02189       $output .= ')';
02190     }
02191   }
02192   elseif (is_bool($var)) {
02193     $output = $var ? 'TRUE' : 'FALSE';
02194   }
02195   elseif (is_string($var) && strpos($var, "\n") !== FALSE) {
02196     // Replace line breaks in strings with a token for replacement
02197     // at the very end. This protects multi-line strings from
02198     // unintentional indentation.
02199     $var = str_replace("\n", "***BREAK***", $var);
02200     $output = var_export($var, TRUE);
02201   }
02202   else {
02203     $output = var_export($var, TRUE);
02204   }
02205 
02206   if ($prefix) {
02207     $output = str_replace("\n", "\n$prefix", $output);
02208   }
02209 
02210   if ($init) {
02211     $output = str_replace("***BREAK***", "\n", $output);
02212   }
02213 
02214   return $output;
02215 }
02216 
02233 function views_clean_css_identifier($identifier, $filter = array(' ' => '-', '/' => '-', '[' => '-', ']' => '')) {
02234   // By default, we filter using Drupal's coding standards.
02235   $identifier = strtr($identifier, $filter);
02236 
02237   // Valid characters in a CSS identifier are:
02238   // - the hyphen (U+002D)
02239   // - a-z (U+0030 - U+0039)
02240   // - A-Z (U+0041 - U+005A)
02241   // - the underscore (U+005F)
02242   // - 0-9 (U+0061 - U+007A)
02243   // - ISO 10646 characters U+00A1 and higher
02244   // We strip out any character not in the above list.
02245   $identifier = preg_replace('/[^\x{002D}\x{0030}-\x{0039}\x{0041}-\x{005A}\x{005F}\x{0061}-\x{007A}\x{00A1}-\x{FFFF}]/u', '', $identifier);
02246 
02247   return $identifier;
02248 }
02249 
02253 function views_views_exportables($op = 'list', $views = NULL, $name = 'foo') {
02254   $all_views = views_get_all_views();
02255   if ($op == 'list') {
02256 
02257     foreach ($all_views as $name => $view) {
02258       // in list, $views is a list of tags.
02259       if (empty($views) || in_array($view->tag, $views)) {
02260         $return[$name] = array(
02261           'name' => check_plain($name),
02262           'desc' => check_plain($view->description),
02263           'tag' => check_plain($view->tag)
02264         );
02265       }
02266     }
02267     return $return;
02268   }
02269 
02270   if ($op == 'export') {
02271     $code = "/**\n";
02272     $code .= " * Implement hook_views_default_views().\n";
02273     $code .= " */\n";
02274     $code .= "function " . $name . "_views_default_views() {\n";
02275     foreach ($views as $view => $truth) {
02276       $code .= "  /*\n";
02277       $code .= "   * View " . var_export($all_views[$view]->name, TRUE) . "\n";
02278       $code .= "   */\n";
02279       $code .= $all_views[$view]->export('  ');
02280       $code .= '  $views[$view->name] = $view;' . "\n\n";
02281     }
02282     $code .= "  return \$views;\n";
02283     $code .= "}\n";
02284 
02285     return $code;
02286   }
02287 }
02288 
02298 function views_process_check_options($element, &$form_state) {
02299   if ($element['#type'] == 'checkboxes' || $element['#type'] == 'checkbox') {
02300     $element['#options'] = array_map('check_plain', $element['#options']);
02301   }
02302   return $element;
02303 }
02304 
02317 function views_trim_text($alter, $value) {
02318   if (drupal_strlen($value) > $alter['max_length']) {
02319     $value = drupal_substr($value, 0, $alter['max_length']);
02320     // TODO: replace this with cleanstring of ctools
02321     if (!empty($alter['word_boundary'])) {
02322       $regex = "(.*)\b.+";
02323       if (function_exists('mb_ereg')) {
02324         mb_regex_encoding('UTF-8');
02325         $found = mb_ereg($regex, $value, $matches);
02326       }
02327       else {
02328         $found = preg_match("/$regex/us", $value, $matches);
02329       }
02330       if ($found) {
02331         $value = $matches[1];
02332       }
02333     }
02334     // Remove scraps of HTML entities from the end of a strings
02335     $value = rtrim(preg_replace('/(?:<(?!.+>)|&(?!.+;)).*$/us', '', $value));
02336 
02337     if (!empty($alter['ellipsis'])) {
02338       $value .= t('...');
02339     }
02340   }
02341   if (!empty($alter['html'])) {
02342     $value = _filter_htmlcorrector($value);
02343   }
02344 
02345   return $value;
02346 }
02347 
02353 function views_array_key_plus($array) {
02354   $keys = array_keys($array);
02355   rsort($keys);
02356   foreach ($keys as $key) {
02357     $array[$key+1] = $array[$key];
02358     unset($array[$key]);
02359   }
02360   asort($array);
02361   return $array;
02362 }
02363 
02367 function views_ctools_plugin_api_hook_name() {
02368   return 'views_api';
02369 }
02370 
02371 // Declare API compatibility on behalf of core modules:
02372 
02378 function views_views_api() {
02379   return array(
02380     // in your modules do *not* use views_api_version()!!!
02381     'api' => views_api_version(),
02382     'path' => drupal_get_path('module', 'views') . '/modules',
02383   );
02384 }
02385 
02386 if (!function_exists('aggregator_views_api')) {
02387   function aggregator_views_api() { return views_views_api(); }
02388 }
02389 
02390 if (!function_exists('book_views_api')) {
02391   function book_views_api() { return views_views_api(); }
02392 }
02393 
02394 if (!function_exists('comment_views_api')) {
02395   function comment_views_api() { return views_views_api(); }
02396 }
02397 
02398 if (!function_exists('field_views_api')) {
02399   function field_views_api() { return views_views_api(); }
02400 }
02401 
02402 if (!function_exists('file_views_api')) {
02403   function file_views_api() { return views_views_api(); }
02404 }
02405 
02406 if (!function_exists('filter_views_api')) {
02407   function filter_views_api() { return views_views_api(); }
02408 }
02409 
02410 if (!function_exists('image_views_api')) {
02411   function image_views_api() { return views_views_api(); }
02412 }
02413 
02414 if (!function_exists('locale_views_api')) {
02415   function locale_views_api() { return views_views_api(); }
02416 }
02417 
02418 if (!function_exists('node_views_api')) {
02419   function node_views_api() { return views_views_api(); }
02420 }
02421 
02422 if (!function_exists('poll_views_api')) {
02423   function poll_views_api() { return views_views_api(); }
02424 }
02425 
02426 if (!function_exists('profile_views_api')) {
02427   function profile_views_api() { return views_views_api(); }
02428 }
02429 
02430 if (!function_exists('search_views_api')) {
02431   function search_views_api() { return views_views_api(); }
02432 }
02433 
02434 if (!function_exists('statistics_views_api')) {
02435   function statistics_views_api() { return views_views_api(); }
02436 }
02437 
02438 if (!function_exists('system_views_api')) {
02439   function system_views_api() { return views_views_api(); }
02440 }
02441 
02442 if (!function_exists('taxonomy_views_api')) {
02443   function taxonomy_views_api() { return views_views_api(); }
02444 }
02445 
02446 if (!function_exists('translation_views_api')) {
02447   function translation_views_api() { return views_views_api(); }
02448 }
02449 
02450 if (!function_exists('upload_views_api')) {
02451   function upload_views_api() { return views_views_api(); }
02452 }
02453 
02454 if (!function_exists('user_views_api')) {
02455   function user_views_api() { return views_views_api(); }
02456 }
02457 
02458 if (!function_exists('contact_views_api')) {
02459   function contact_views_api() { return views_views_api(); }
02460 }

Generated on Sun Feb 26 2012 12:52:52 for Views by  doxygen 1.7.1