'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;
}