'theme.inc', 'path' => "$path/theme", ); $arguments = array( 'display' => array('view' => NULL), 'style' => array('view' => NULL, 'options' => NULL, 'rows' => NULL), 'row' => array('view' => NULL, 'options' => NULL, 'row' => NULL), ); // Default view themes $hooks['views_view'] = $base + array( 'template' => 'views-view', 'pattern' => 'views_view__', 'arguments' => $arguments['display'], ); $hooks['views_view_rows'] = $base + array( 'template' => 'views-view-rows', 'pattern' => 'views_view_rows__', 'arguments' => $arguments['style'], ); $hooks['views_view_row'] = $base + array( 'template' => 'views-view-row', 'pattern' => 'views_view_row__', 'arguments' => $arguments['row'], ); $hooks['views_view_field'] = $base + array( 'pattern' => 'views_view_field__', 'arguments' => array('view' => NULL, 'field' => NULL, 'row' => NULL), ); $plugins = views_fetch_plugin_data(); // Register theme functions for all style plugins foreach ($plugins as $type => $info) { foreach ($info as $plugin => $def) { if (isset($def['theme'])) { $hooks[$def['theme']] = array( 'pattern' => $def['theme'] . '__', 'file' => $def['file'], 'path' => $def['path'], 'arguments' => $arguments[$type], ); if (!function_exists('theme_' . $def['theme'])) { $hooks[$def['theme']]['template'] = views_css_safe($def['theme']); } } } } return $hooks; } /** * Implementation of hook_menu(). * * This probably needs to actually be hook_menu_alter or something. */ function views_menu() { $items = array(); foreach (views_get_page_views() as $data) { list($view, $display_id) = $data; $items += $view->execute_hook_menu($display_id); } return $items; } /** * Helper function for menu loading. This will automatically be * called in order to 'load' a views argument; primarily it * will be used to perform validation. * * @param $value * The actual value passed. * @param $name * The name of the view. This needs to be specified in the 'load function' * of the menu entry. * @param $index * The menu argument index. This counts from 1. */ function views_arg_load($value, $name, $index) { if ($v = views_get_view($name)) { $view = drupal_clone($v); $view->init_handlers(); if (isset($view->argument[$index - 1])) { return $view->argument[$index - 1]->handler->validate($value); } } } /** * Page callback entry point; requires a view and a display id, then * passes control to the display handler. */ function views_page() { $args = func_get_args(); $name = array_shift($args); $display_id = array_shift($args); // Load the view if ($v = views_get_view($name)) { $view = drupal_clone($v); return $view->execute_display($display_id, $args); } // Fallback; if we get here no view was found or handler was not valid. return drupal_not_found(); } /** * Implementation of hook_block */ function views_block($op = 'list', $delta = 0, $edit = array()) { switch ($op) { case 'list': $items = array(); foreach (views_get_block_views() as $data) { list($view, $display_id) = $data; $items += $view->execute_hook_block($display_id); } return $items; case 'configure': case 'list': case 'view': list($name, $display_id) = explode('-', $delta); // Load the view if ($v = views_get_view($name)) { $view = drupal_clone($v); if ($view->access($display_id)) { return $view->execute_display($display_id); } } break; } } /** * Implementation of hook_devel_caches(). * * When the devel cache is cleared, clear cached views, too. That * makes development a bit easier. */ function views_devel_caches() { return array('cache_views'); } /** * Determine if the given user has access to the view + display. * * @param $view * May be a view object, or an array with the view name and the display ID, * or a string to use as the view name. * @param $account * An optional account to use; if left off, the current user will be used. */ function views_access($view, $account = NULL) { if (is_array($view)) { list($name, $display_id) = $view; $v = views_get_view($name); if (!$v) { return FALSE; } $view = drupal_clone($v); } elseif (is_string($view)) { $v = views_get_view($view); if (!$v) { return FALSE; } $view = drupal_clone($v); $display_id = 'default'; } else { $view = drupal_clone($view); $display_id = isset($view->current_display) ? $view->current_display : 'default'; } return $view->access($display_id, $account); } /** * Set the current 'page view' that is being displayed so that it is easy * for other modules or the theme to identify. */ function &views_set_page_view($view = NULL) { static $cache = NULL; if (isset($view)) { $cache = $view; } return $cache; } /** * Find out what, if any, page view is currently in use. Please note that * this returns a reference, so be careful! You can unintentionally modify the * $view object. */ function &views_get_page_view() { return views_set_page_view(); } /** * Set the current 'current view' that is being built/rendered so that it is * easy for other modules or items in drupal_eval to identify */ function &views_set_current_view($view = NULL) { static $cache = NULL; if (isset($view)) { $cache = $view; } return $cache; } /** * Find out what, if any, current view is currently in use. Please note that * this returns a reference, so be careful! You can unintentionally modify the * $view object. */ function &views_get_current_view() { return views_set_current_view(); } /** * Include views .inc files as necessary. */ function views_include($file) { static $used = array(); if (!isset($used[$file])) { require_once drupal_get_path('module', 'views') . "/includes/$file.inc"; } $used[$file] = TRUE; } /** * Include views .css files. */ function views_add_css($file) { drupal_add_css(drupal_get_path('module', 'views') . "/css/$file.css"); } /** * Include views .js files. */ function views_add_js($file) { static $base = TRUE; if ($base) { drupal_add_js(drupal_get_path('module', 'views') . "/js/base.js"); } drupal_add_js(drupal_get_path('module', 'views') . "/js/$file.js"); } /** * Prepare the specified string for use as a CSS identifier. */ function views_css_safe($string) { return str_replace('_', '-', $string); } // ----------------------------------------------------------------------- // Views handler functions /** * Load views files on behalf of modules. */ function views_include_handlers() { static $finished = FALSE; // Ensure this only gets run once. if ($finished) { return; } views_include('handlers'); views_include('cache'); views_include('plugins'); _views_include_handlers(); $finished = TRUE; } /** * Load default views files on behalf of modules. */ function views_include_default_views() { static $finished = FALSE; // Ensure this only gets run once. if ($finished) { return; } // Default views hooks may be in the normal handler file, // or in a separate views_default file at the discretion of // the module author. views_include_handlers(); _views_include_default_views(); $finished = TRUE; } /** * Fetch a handler from the data cache. */ function views_get_handler($table, $field, $key) { $data = views_fetch_data($table); if (isset($data[$field][$key])) { return _views_prepare_handler($data[$field][$key], $data, $field); } // DEBUG -- identify missing handlers vpr("Missing handler: $table $field $key"); } /** * Fetch Views' data from the cache */ function views_fetch_data($table = NULL) { views_include('cache'); return _views_fetch_data($table); } /** * Fetch a list of all base tables available * * @return * A keyed array of in the form of 'base_table' => 'Description'. */ function views_fetch_base_table_names() { static $base_tables = array(); if (empty($base_tables)) { $data = views_fetch_data(); foreach ($data as $table => $info) { if (!empty($info['table']['base'])) { $base_tables[$table] = $info['table']['base']['title'] . '
' . $info['table']['base']['help'] . "
\n"; } } } return $base_tables; } /** * Fetch a list of all base tables available * * @return * A keyed array of in the form of 'base_table' => 'Description'. */ function views_fetch_field_names($base, $type) { static $fields = array(); if (empty($fields)) { $data = views_fetch_data(); $start = microtime(); foreach ($data as $table => $table_data) { $bases = array(); $strings = array(); foreach ($table_data as $field => $info) { // Collect table data from this table if ($field == 'table') { // calculate what tables this table can join to. if (!empty($info['join'])) { $bases = array_keys($info['join']); } // And if this table IS a base table it obviously joins to itself. if (!empty($info['base'])) { $bases[] = $table; } continue; } foreach (array('field', 'sort', 'filter', 'argument') as $key) { if (!empty($info[$key])) { foreach (array('title', 'group', 'help') as $string) { // First, try the lowest possible level if (!empty($info[$key][$string])) { $strings[$field][$key][$string] = $info[$key][$string]; } // Then try the field level elseif (!empty($info[$string])) { $strings[$field][$key][$string] = $info[$string]; } // Finally, try the table level elseif (!empty($table_data['table'][$string])) { $strings[$field][$key][$string] = $table_data['table'][$string]; } else { $strings[$field][$key][$string] = t("Error: missing @component", array('@component' => $string)); } } } } } foreach ($bases as $base_name) { foreach ($strings as $field => $field_strings) { foreach ($field_strings as $type_name => $type_strings) { $fields[$base_name][$type_name]["$table.$field"] = t('@group: @field
@help
', array('@group' => $type_strings['group'], '@field' => $type_strings['title'], '@help' => $type_strings['help'])); } } } } // vsm('Views UI data build time: ' . (microtime() - $start) * 1000 . ' ms'); } if (isset($fields[$base][$type])) { asort($fields[$base][$type]); return $fields[$base][$type]; } return array(); } // ----------------------------------------------------------------------- // Views plugin functions /** * Fetch the plugin data from cache. */ function views_fetch_plugin_data($type = NULL, $plugin = NULL) { views_include('cache'); return _views_fetch_plugin_data($type, $plugin); } /** * Get a handler for a plugin */ function views_get_plugin($type, $plugin) { $definition = views_fetch_plugin_data($type, $plugin); if (!empty($definition)) { return _views_create_handler($definition); } } /** * Fetch a list of all base tables available * * @return * A keyed array of in the form of 'base_table' => 'Description'. */ function views_fetch_plugin_names($type, $key = NULL, $empty = FALSE) { $data = views_fetch_plugin_data(); $plugins[$type] = array(); foreach ($data[$type] as $id => $plugin) { // Skip plugins that don't conform to our key. if ($key && (($empty && empty($plugin[$key])) || (!$empty && !empty($plugin[$key])))) { continue; } if (empty($plugin['no ui'])) { $plugins[$type][$id] = $plugin['title']; } } if (!empty($plugins[$type])) { asort($plugins[$type]); return $plugins[$type]; } // fall-through return array(); } // ----------------------------------------------------------------------- // Views database functions /** * Get a view from the default views defined by modules. * * Default views are cached per-language. This function will rescan the * default_views hook if necessary. * * @param $view_name * The name of the view to load. * @return * A view object or NULL if it is not available. */ function &views_get_default_view($view_name) { $null = NULL; $cache = views_discover_default_views(); if (isset($cache[$view_name])) { return $cache[$view_name]; } return $null; } /** * Create an empty view to work with. * * @return * A fully formed, empty $view object. This object must be populated before * it can be successfully saved. */ function views_new_view() { views_include('view'); $view = new view(); $view->vid = 'new'; $view->add_display('default'); return $view; } /** * Scan all modules for default views and rebuild the default views cache. * * @return An associative array of all known default views. */ function views_discover_default_views() { static $cache = array(); if (empty($cache)) { views_include('cache'); $cache = _views_discover_default_views(); } return $cache; } /** * Get a list of all views and the display plugins that provide * page support to the Drupal menu system. Since views can appear * in this list multiple times, the return of this function is an * array of arrays. * * @return * @code * array( * array($view, $display_id), * array($view, $display_id), * ); * @endcode */ function views_get_page_views() { return views_get_applicable_views('uses hook menu'); } /** * Get a list of all views and the display plugins that provide * themselves to the Drupal block system. Since views can appear * in this list multiple times, the return of this function is an * array of arrays. * * @return * @code * array( * array($view, $display_id), * array($view, $display_id), * ); * @endcode */ function views_get_block_views() { return views_get_applicable_views('uses hook block'); } /** * Return a list of all views and display IDs that have a particular * setting in their display's plugin settings. * * @return * @code * array( * array($view, $display_id), * array($view, $display_id), * ); * @endcode */ function views_get_applicable_views($type) { $result = array(); $views = views_get_all_views(); foreach ($views as $view) { // Skip disabled views. if (!empty($view->disabled)) { continue; } foreach ($view->display as $display) { $plugin = views_fetch_plugin_data('display', $display->display_plugin); if (!empty($plugin[$type])) { // This view uses hook menu. Clone it so that different handlers // don't trip over each other, and add it to the list. $v = drupal_clone($view); if ($v->set_display($display->id)) { $result[] = array($v, $display->id); } } } } return $result; } /** * Return an array of all views as fully loaded $view objects. */ function views_get_all_views() { static $views = array(); if (empty($views)) { // First, get all applicable views. views_include('view'); $views = view::load_views(); // Get all default views. $status = variable_get('panel_page_defaults', array()); foreach (views_discover_default_views() as $view) { // Determine if default view is enabled or disabled. if (isset($status[$view->name])) { $view->disabled = $status[$view->name]; } // If overridden, also say so. if (!empty($views[$view->name])) { $views[$view->name]->type = t('Overridden'); } else { $view->type = t('Default'); $views[$view->name] = $view; } } } return $views; } /** * Get a view from the database or from default views. * * This function is just a static wrapper around views::load(). This function * isn't called 'views_load()' primarily because it might get a view * from the default views which aren't technically loaded from the database. * * @param $name * The name of the view. * @param $reset * If TRUE, reset this entry in the load cache. * @return $view * A reference to the $view object. Use $reset if you're sure you want * a fresh one. */ function views_get_view($name, $reset = FALSE) { views_include('view'); $view = view::load($name, $reset); $default_view = views_get_default_view($name); if (empty($view) && empty($default_view)) { return; } elseif (empty($view) && !empty($default_view)) { $default_view->type = t('Default'); return $default_view; } elseif (!empty($view) && !empty($default_view)) { $view->type = t('Overridden'); return $view; } return $view; } /** * Basic definition for many views objects */ class views_object { /** * Views handlers use a special construct function so that we can more * easily construct them with variable arguments. */ function construct() { } /** * Let the handler know what its full definition is. */ function set_definition($definition) { $this->definition = $definition; if (isset($definition['field'])) { $this->real_field = $definition['field']; } } } /** * Provide debug output for Views. This relies on devel.module */ function views_debug($message) { if (module_exists('devel')) { drupal_set_content('footer', dpr($message, TRUE)); } } /** * Shortcut to views_debug() */ function vpr($message) { views_debug($message); } /** * Debug messages */ function vsm($message) { if (module_exists('devel')) { dsm($message); } } function views_trace() { $message = ''; foreach (debug_backtrace() as $item) { if (!empty($item['file']) && !in_array($item['function'], array('vsm_trace', 'vpr_trace', 'views_trace'))) { $message .= basename($item['file']) . ": " . (empty($item['class']) ? '' : ($item['class'] . '->')) . "$item[function] line $item[line]" . "\n"; } } return $message; } function vsm_trace() { vsm(views_trace()); } function vpr_trace() { dpr(views_trace()); } function views_object_types() { return array( 'field' => array( 'title' => t('Fields'), 'stitle' => t('Field'), 'plural' => 'fields', 'object' => 'views_field', ), 'argument' => array( 'title' => t('Arguments'), 'stitle' => t('Argument'), 'plural' => 'arguments', 'object' => 'views_argument', ), 'sort' => array( 'title' => t('Sort criteria'), 'stitle' => t('Sort criterion'), 'plural' => 'sorts', 'object' => 'views_sort', ), 'filter' => array( 'title' => t('Filters'), 'stitle' => t('Filter'), 'plural' => 'filters', 'object' => 'views_filter', ), 'relationship' => array( 'title' => t('Relationships'), 'stitle' => t('Relationship'), 'plural' => 'relationships', 'object' => 'views_relationship', ), ); } /** * Figure out what timezone we're in; needed for some date manipulations. */ function views_get_timezone() { global $user; if (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) { $timezone = $user->timezone; } else { $timezone = variable_get('date_default_timezone', 0); } // set up the database timezone if (in_array($GLOBALS['db_type'], array('mysql', 'mysqli'))) { static $already_set = false; if (!$already_set) { if ($GLOBALS['db_type'] == 'mysqli' || version_compare(mysql_get_server_info(), '4.1.3', '>=')) { db_query("SET @@session.time_zone = '+00:00'"); } $already_set = true; } } return $timezone; }