Newer
Older
The Great Git Migration
committed
<?php
/**
* @file
* Primarily Drupal hooks and global API functions to manipulate views.
*
* This is the main module file for Views. The main entry points into
* this module are views_page() and views_block(), where it handles
* incoming page and block requests.
*/
/**
* Advertise the current views api version
*/
function views_api_version() {
Daniel Wehner
committed
return '3.0-alpha1';
}
/**
* Views will not load plugins advertising a version older than this.
*/
function views_api_minimum_version() {
return '2';
The Great Git Migration
committed
}
Daniel Wehner
committed
/**
* Implement hook_init().
*/
function views_init() {
drupal_add_css(drupal_get_path('module', 'views') .'/css/views.css');
}
The Great Git Migration
committed
/**
* Implement hook_theme(). Register views theming functions.
The Great Git Migration
committed
*/
Daniel Wehner
committed
function views_theme($existing, $type, $theme, $path) {
The Great Git Migration
committed
$path = drupal_get_path('module', 'views');
include_once $path . '/theme/theme.inc';
The Great Git Migration
committed
// Some quasi clever array merging here.
$base = array(
'file' => 'theme.inc',
'path' => $path . '/theme',
The Great Git Migration
committed
);
// Our extra version of pager from pager.inc
$hooks['views_mini_pager'] = $base + array(
'variables' => array('tags' => array(), 'quantity' => 10, 'element' => 0, 'parameters' => array()),
The Great Git Migration
committed
'pattern' => 'views_mini_pager__',
);
$arguments = array(
'display' => array('view' => NULL),
'style' => array('view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL),
'row' => array('view' => NULL, 'options' => NULL, 'row' => NULL, 'field_alias' => NULL),
);
// Default view themes
$hooks['views_view_field'] = $base + array(
'pattern' => 'views_view_field__',
'variables' => array('view' => NULL, 'field' => NULL, 'row' => NULL),
The Great Git Migration
committed
);
$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['theme file'],
'path' => $def['theme path'],
'variables' => $arguments[$type],
The Great Git Migration
committed
);
$include = DRUPAL_ROOT . '/' . $def['theme path'] . '/' . $def['theme file'];
The Great Git Migration
committed
if (file_exists($include)) {
require_once $include;
}
if (!function_exists('theme_' . $def['theme'])) {
$hooks[$def['theme']]['template'] = drupal_clean_css_identifier($def['theme']);
The Great Git Migration
committed
}
}
if (isset($def['additional themes'])) {
foreach ($def['additional themes'] as $theme => $theme_type) {
if (empty($theme_type)) {
$theme = $theme_type;
$theme_type = $type;
}
$hooks[$theme] = array(
'pattern' => $theme . '__',
'file' => $def['theme file'],
'path' => $def['theme path'],
'variables' => $arguments[$theme_type],
The Great Git Migration
committed
);
if (!function_exists('theme_' . $theme)) {
$hooks[$theme]['template'] = drupal_clean_css_identifier($theme);
The Great Git Migration
committed
}
}
}
}
}
$hooks['views_exposed_form'] = $base + array(
'template' => 'views-exposed-form',
'pattern' => 'views_exposed_form__',
'render element' => 'form',
The Great Git Migration
committed
);
$hooks['views_more'] = $base + array(
'template' => 'views-more',
'pattern' => 'views_more__',
'variables' => array('more_url' => NULL, 'link_text' => 'more'),
The Great Git Migration
committed
);
Daniel Wehner
committed
// Add theme suggestions which are part of modules.
foreach (views_get_module_apis() as $info) {
if (isset($info['template path'])) {
$hooks += _views_find_module_templates($hooks, $info['template path']);
}
}
The Great Git Migration
committed
return $hooks;
}
Daniel Wehner
committed
/**
* Scans a directory of a module for template files.
*
* @param $cache
* The existing cache of theme hooks to test against.
* @param $path
* The path to search.
*
Daniel Wehner
committed
* @see drupal_find_theme_templates
*/
function _views_find_module_templates($cache, $path) {
$regex = '/' . '\.tpl\.php' . '$' . '/';
Daniel Wehner
committed
// Because drupal_system_listing works the way it does, we check for real
// templates separately from checking for patterns.
$files = drupal_system_listing($regex, $path, 'name', 0);
foreach ($files as $template => $file) {
// Chop off the remaining extensions if there are any. $template already
// has the rightmost extension removed, but there might still be more,
// such as with .tpl.php, which still has .tpl in $template at this point.
if (($pos = strpos($template, '.')) !== FALSE) {
$template = substr($template, 0, $pos);
}
// Transform - in filenames to _ to match function naming scheme
// for the purposes of searching.
$hook = strtr($template, '-', '_');
if (isset($cache[$hook])) {
$templates[$hook] = array(
'template' => $template,
'path' => dirname($file->filename),
'includes' => isset($cache[$hook]['includes']) ? $cache[$hook]['includes'] : NULL,
Daniel Wehner
committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
);
}
// Ensure that the pattern is maintained from base themes to its sub-themes.
// Each sub-theme will have their templates scanned so the pattern must be
// held for subsequent runs.
if (isset($cache[$hook]['pattern'])) {
$templates[$hook]['pattern'] = $cache[$hook]['pattern'];
}
}
$patterns = array_keys($files);
foreach ($cache as $hook => $info) {
if (!empty($info['pattern'])) {
// Transform _ in pattern to - to match file naming scheme
// for the purposes of searching.
$pattern = strtr($info['pattern'], '_', '-');
$matches = preg_grep('/^'. $pattern .'/', $patterns);
if ($matches) {
foreach ($matches as $match) {
$file = substr($match, 0, strpos($match, '.'));
// Put the underscores back in for the hook name and register this pattern.
$templates[strtr($file, '-', '_')] = array(
'template' => $file,
'path' => dirname($files[$match]->filename),
'variables' => $info['variables'],
'base hook' => $hook,
'includes' => isset($info['includes']) ? $info['includes'] : NULL,
Daniel Wehner
committed
);
}
}
}
}
return $templates;
}
The Great Git Migration
committed
/**
* A theme preprocess function to automatically allow view-based node
* templates if called from a view.
*
* The 'modules/node.views.inc' file is a better place for this, but
* we haven't got a chance to load that file before Drupal builds the
* node portion of the theme registry.
*/
function views_preprocess_node(&$vars) {
// The 'view' attribute of the node is added in template_preprocess_views_view_row_node()
if (!empty($vars['node']->view) && !empty($vars['node']->view->name)) {
$vars['view'] = &$vars['node']->view;
Daniel Wehner
committed
$vars['theme_hook_suggestions'][] = 'node__view__' . $vars['node']->view->name;
if (!empty($vars['node']->view->current_display)) {
Daniel Wehner
committed
$vars['theme_hook_suggestions'][] = 'node__view__' . $vars['node']->view->name . '__' . $vars['node']->view->current_display;
The Great Git Migration
committed
}
}
}
/**
* A theme preprocess function to automatically allow view-based node
* templates if called from a view.
*/
function views_preprocess_comment(&$vars) {
// The 'view' attribute of the node is added in template_preprocess_views_view_row_comment()
if (!empty($vars['node']->view) && !empty($vars['node']->view->name)) {
$vars['view'] = &$vars['node']->view;
Daniel Wehner
committed
$vars['theme_hook_suggestions'][] = 'comment__view__' . $vars['node']->view->name;
if (!empty($vars['node']->view->current_display)) {
Daniel Wehner
committed
$vars['theme_hook_suggestions'][] = 'comment__view__' . $vars['node']->view->name . '__' . $vars['node']->view->current_display;
The Great Git Migration
committed
}
}
}
/*
* Implement hook_permission().
The Great Git Migration
committed
*/
function views_permission() {
return array(
'administer views' => array(
'title' => t('Administer views'),
'description' => t('Access the views administration pages.'),
),
'access all views' => array(
'title' => t('Bypass views access control'),
'description' => t('Bypass access control when accessing views.'),
),
);
The Great Git Migration
committed
}
/**
* Implement hook_menu().
The Great Git Migration
committed
*/
function views_menu() {
// Any event which causes a menu_rebuild could potentially mean that the
// Views data is updated -- module changes, profile changes, etc.
views_invalidate_cache();
$items = array();
$items['views/ajax'] = array(
'title' => 'Views',
'page callback' => 'views_ajax',
'delivery callback' => 'ajax_deliver',
The Great Git Migration
committed
'access callback' => TRUE,
'description' => 'Ajax callback for view loading.',
'type' => MENU_CALLBACK,
'file' => 'includes/ajax.inc',
The Great Git Migration
committed
);
// Path is not admin/structure/views due to menu complications with the wildcards from
The Great Git Migration
committed
// the generic ajax callback.
$items['admin/views/ajax/autocomplete/user'] = array(
'page callback' => 'views_ajax_autocomplete_user',
'access callback' => 'user_access',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
'file' => 'includes/ajax.inc',
The Great Git Migration
committed
);
// Define another taxonomy autocomplete because the default one of drupal
// does not support a vid a argument anymore
$items['admin/views/ajax/autocomplete/taxonomy'] = array(
'page callback' => 'views_ajax_autocomplete_taxonomy',
'access callback' => 'user_access',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
'file' => 'includes/ajax.inc',
);
The Great Git Migration
committed
return $items;
}
/**
* Implement hook_menu_alter().
The Great Git Migration
committed
*/
function views_menu_alter(&$callbacks) {
$our_paths = array();
$views = views_get_applicable_views('uses hook menu');
foreach ($views as $data) {
list($view, $display_id) = $data;
Earl Miles
committed
$result = $view->execute_hook_menu($display_id, $callbacks);
The Great Git Migration
committed
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
if (is_array($result)) {
// The menu system doesn't support having two otherwise
// identical paths with different placeholders. So we
// want to remove the existing items from the menu whose
// paths would conflict with ours.
// First, we must find any existing menu items that may
// conflict. We use a regular expression because we don't
// know what placeholders they might use. Note that we
// first construct the regex itself by replacing %views_arg
// in the display path, then we use this constructed regex
// (which will be something like '#^(foo/%[^/]*/bar)$#') to
// search through the existing paths.
$regex = '#^(' . preg_replace('#%views_arg#', '%[^/]*', implode('|', array_keys($result))) . ')$#';
$matches = preg_grep($regex, array_keys($callbacks));
// Remove any conflicting items that were found.
foreach ($matches as $path) {
// Don't remove the paths we just added!
if (!isset($our_paths[$path])) {
unset($callbacks[$path]);
}
}
foreach ($result as $path => $item) {
if (!isset($callbacks[$path])) {
// Add a new item, possibly replacing (and thus effectively
// overriding) one that we removed above.
$callbacks[$path] = $item;
}
else {
// This item already exists, so it must be one that we added.
// We change the various callback arguments to pass an array
// of possible display IDs instead of a single ID.
$callbacks[$path]['page arguments'][1] = (array)$callbacks[$path]['page arguments'][1];
$callbacks[$path]['page arguments'][1][] = $display_id;
$callbacks[$path]['access arguments'][] = $item['access arguments'][0];
$callbacks[$path]['load arguments'][1] = (array)$callbacks[$path]['load arguments'][1];
$callbacks[$path]['load arguments'][1][] = $display_id;
}
$our_paths[$path] = TRUE;
}
}
}
// Save memory: Destroy those views.
foreach ($views as $data) {
list($view, $display_id) = $data;
$view->destroy();
}
}
/**
* 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.
Earl Miles
committed
* @param $display_id
* The display id that will be loaded for this menu item.
The Great Git Migration
committed
* @param $index
* The menu argument index. This counts from 1.
*/
function views_arg_load($value, $name, $display_id, $index) {
Earl Miles
committed
static $views = array();
// Make sure we haven't already loaded this views argument for a similar menu
// item elsewhere.
$key = $name . ':' . $display_id . ':' . $value . ':' . $index;
if (isset($views[$key])) {
return $views[$key];
}
The Great Git Migration
committed
if ($view = views_get_view($name)) {
$view->set_display($display_id);
$view->init_handlers();
$ids = array_keys($view->argument);
$indexes = array();
$path = explode('/', $view->get_path());
foreach ($path as $id => $piece) {
if ($piece == '%' && !empty($ids)) {
$indexes[$id] = array_shift($ids);
}
}
if (isset($indexes[$index])) {
if (isset($view->argument[$indexes[$index]])) {
$arg = $view->argument[$indexes[$index]]->validate_argument($value) ? $value : FALSE;
$view->destroy();
Earl Miles
committed
// Store the output in case we load this same menu item again.
$views[$key] = $arg;
The Great Git Migration
committed
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
return $arg;
}
}
$view->destroy();
}
}
/**
* 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 ($view = views_get_view($name)) {
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();
}
/**
* Implement hook_block_info().
The Great Git Migration
committed
*/
function views_block_info() {
Earl Miles
committed
// Try to avoid instantiating all the views just to get the blocks info.
views_include('cache');
$cache = views_cache_get('views_block_items', TRUE);
if ($cache && is_array($cache->data)) {
return $cache->data;
}
$items = array();
$views = views_get_all_views();
foreach ($views as $view) {
// disabled views get nothing.
if (!empty($view->disabled)) {
continue;
}
The Great Git Migration
committed
$view->init_display();
foreach ($view->display as $display_id => $display) {
The Great Git Migration
committed
if (isset($display->handler) && !empty($display->handler->definition['uses hook block'])) {
$result = $display->handler->execute_hook_block_list();
if (is_array($result)) {
$items = array_merge($items, $result);
The Great Git Migration
committed
}
}
if (isset($display->handler) && $display->handler->get_option('exposed_block')) {
$result = $display->handler->get_special_blocks();
if (is_array($result)) {
$items = array_merge($items, $result);
The Great Git Migration
committed
}
}
}
}
The Great Git Migration
committed
// block.module has a delta length limit of 32, but our deltas can
// unfortunately be longer because view names can be 32 and display IDs
// can also be 32. So for very long deltas, change to md5 hashes.
$hashes = array();
// get the keys because we're modifying the array and we don't want to
// confuse PHP too much.
$keys = array_keys($items);
foreach ($keys as $delta) {
if (strlen($delta) >= 32) {
$hash = md5($delta);
$hashes[$hash] = $delta;
$items[$hash] = $items[$delta];
unset($items[$delta]);
}
}
The Great Git Migration
committed
Daniel Wehner
committed
// Only save hashes if they have changed.
$old_hashes = variable_get('views_block_hashes', array());
if ($hashes != $old_hashes) {
variable_set('views_block_hashes', $hashes);
}
// Save memory: Destroy those views.
foreach ($views as $view) {
$view->destroy();
}
The Great Git Migration
committed
Earl Miles
committed
views_cache_set('views_block_items', $items, TRUE);
return $items;
}
/**
* Implement hook_block_view().
*/
function views_block_view($delta) {
$start = microtime(TRUE);
// if this is 32, this should be an md5 hash.
if (strlen($delta) == 32) {
$hashes = variable_get('views_block_hashes', array());
if (!empty($hashes[$delta])) {
$delta = $hashes[$delta];
}
}
The Great Git Migration
committed
// This indicates it's a special one.
if (substr($delta, 0, 1) == '-') {
list($nothing, $type, $name, $display_id) = explode('-', $delta);
// Put the - back on.
$type = '-' . $type;
if ($view = views_get_view($name)) {
if ($view->access($display_id)) {
$view->set_display($display_id);
if (isset($view->display_handler)) {
$output = $view->display_handler->view_special_blocks($type);
The Great Git Migration
committed
$view->destroy();
return $output;
}
}
$view->destroy();
}
}
list($name, $display_id) = explode('-', $delta);
// Load the view
if ($view = views_get_view($name)) {
if ($view->access($display_id)) {
$output = $view->execute_display($display_id);
$view->destroy();
return $output;
}
$view->destroy();
The Great Git Migration
committed
}
}
/**
Daniel Wehner
committed
* Implements hook_flush_caches().
The Great Git Migration
committed
*/
function views_flush_caches() {
return array('cache_views', 'cache_views_data');
}
Daniel Wehner
committed
/**
* Implements hook_field_create_instance.
*/
function views_field_create_instance($instance) {
cache_clear_all('*', 'cache_views', TRUE);
cache_clear_all('*', 'cache_views_data', TRUE);
}
/**
* Implements hook_field_update_instance.
*/
function views_field_update_instance($instance, $prior_instance) {
cache_clear_all('*', 'cache_views', TRUE);
cache_clear_all('*', 'cache_views_data', TRUE);
}
/**
* Implements hook_field_delete_instance.
*/
function views_field_delete_instance($instance) {
cache_clear_all('*', 'cache_views', TRUE);
cache_clear_all('*', 'cache_views_data', TRUE);
}
The Great Git Migration
committed
/**
* Invalidate the views cache, forcing a rebuild on the next grab of table data.
*/
function views_invalidate_cache() {
cache_clear_all('*', 'cache_views', TRUE);
The Great Git Migration
committed
}
/**
* Access callback to determine if the user can import Views.
*
* View imports require an additional access check because they are PHP
* code and PHP is more locked down than administer views.
*/
function views_import_access() {
Daniel Wehner
committed
return user_access('administer views') && user_access('use PHP for settings');
The Great Git Migration
committed
/**
* Determine if the logged in user has access to a view.
*
* This function should only be called from a menu hook or some other
* embedded source. Each argument is the result of a call to
* views_plugin_access::get_access_callback() which is then used
* to determine if that display is accessible. If *any* argument
* is accessible, then the view is accessible.
*/
function views_access() {
$args = func_get_args();
foreach ($args as $arg) {
if ($arg === TRUE) {
return TRUE;
}
if (!is_array($arg)) {
continue;
}
list($callback, $arguments) = $arg;
$arguments = $arguments ? $arguments : array();
// Bring dynamic arguments to the access callback.
foreach ($arguments as $key => $value) {
if (is_int($value) && isset($args[$value])) {
$arguments[$key] = $args[$value];
}
}
The Great Git Migration
committed
if (function_exists($callback) && call_user_func_array($callback, $arguments)) {
return TRUE;
}
}
return FALSE;
}
/**
Earl Miles
committed
* Access callback for the views_plugin_access_perm access plugin.
The Great Git Migration
committed
*
Earl Miles
committed
* Determine if the specified user has access to a view on the basis of
* permissions. If the $account argument is omitted, the current user
* is used.
*/
function views_check_perm($perm, $account = NULL) {
return user_access($perm, $account) || user_access('access all views', $account);
}
/**
* Access callback for the views_plugin_access_role access plugin.
* Determine if the specified user has access to a view on the basis of any of
* the requested roles. If the $account argument is omitted, the current user
* is used.
The Great Git Migration
committed
*/
Earl Miles
committed
function views_check_roles($rids, $account = NULL) {
The Great Git Migration
committed
global $user;
Earl Miles
committed
$account = isset($account) ? $account : $user;
$roles = array_keys($account->roles);
$roles[] = $account->uid ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID;
return user_access('access all views', $account) || array_intersect(array_filter($rids), $roles);
The Great Git Migration
committed
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
}
// ------------------------------------------------------------------
// Functions to help identify views that are running or ran
/**
* 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 file helpers
/**
* Include views .inc files as necessary.
*/
function views_include($file) {
module_load_include('inc', 'views', "includes/$file");
The Great Git Migration
committed
}
/**
* Load views files on behalf of modules.
*/
Daniel Wehner
committed
function views_module_include($file, $reset = FALSE) {
foreach (views_get_module_apis($reset) as $module => $info) {
if (file_exists(DRUPAL_ROOT . "/$info[path]/$module.$file")) {
require_once DRUPAL_ROOT . "/$info[path]/$module.$file";
The Great Git Migration
committed
}
}
}
/**
* Get a list of modules that support the current views API.
*/
Daniel Wehner
committed
function views_get_module_apis($reset = FALSE) {
The Great Git Migration
committed
static $cache = NULL;
Daniel Wehner
committed
if (!isset($cache) || $reset) {
The Great Git Migration
committed
$cache = array();
foreach (module_implements('views_api') as $module) {
$info = module_invoke($module, 'views_api');
Daniel Wehner
committed
if (version_compare($info['api'], views_api_minimum_version(), '>=') &&
version_compare($info['api'], views_api_version(), '<=')) {
if (!isset($info['path'])) {
$info['path'] = drupal_get_path('module', $module);
}
Daniel Wehner
committed
$cache[$module] = $info;
The Great Git Migration
committed
}
}
}
return $cache;
}
/**
* Include views .css files.
*/
function views_add_css($file) {
// We set preprocess to FALSE because we are adding the files conditionally,
// and we don't want to generate duplicate cache files.
// TODO: at some point investigate adding some files unconditionally and
// allowing preprocess.
drupal_add_css(drupal_get_path('module', 'views') . "/css/$file.css", array('preprocess' => FALSE));
The Great Git Migration
committed
}
/**
* Include views .js files.
*/
function views_add_js($file) {
// If javascript has been disabled by the user, never add js files.
if (variable_get('views_no_javascript', FALSE)) {
return;
}
static $base = TRUE, $ajax = TRUE;
The Great Git Migration
committed
if ($base) {
drupal_add_js(drupal_get_path('module', 'views') . "/js/base.js");
$base = FALSE;
}
if ($ajax && in_array($file, array('ajax', 'ajax_view'))) {
drupal_add_library('system', 'drupal.ajax');
drupal_add_library('system', 'jquery.form');
$ajax = FALSE;
}
ctools_add_js($file, 'views');
The Great Git Migration
committed
}
/**
* Load views files on behalf of modules.
*/
Daniel Wehner
committed
function views_include_handlers($reset = FALSE) {
The Great Git Migration
committed
static $finished = FALSE;
// Ensure this only gets run once.
Daniel Wehner
committed
if ($finished && !$reset) {
The Great Git Migration
committed
return;
}
views_include('base');
views_include('handlers');
views_include('cache');
views_include('plugins');
_views_include_handlers();
$finished = TRUE;
}
/**
* Load default views files on behalf of modules.
*/
Daniel Wehner
committed
function views_include_default_views($reset = FALSE) {
The Great Git Migration
committed
static $finished = FALSE;
// Ensure this only gets run once.
Daniel Wehner
committed
if ($finished && !$reset) {
The Great Git Migration
committed
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.
Daniel Wehner
committed
views_include_handlers($reset);
The Great Git Migration
committed
Daniel Wehner
committed
_views_include_default_views($reset);
The Great Git Migration
committed
$finished = TRUE;
}
// -----------------------------------------------------------------------
// Views handler functions
/**
* Fetch a handler from the data cache.
*
* @param $table
* The name of the table this handler is from.
* @param $field
* The name of the field this handler is from.
* @param $key
* The type of handler. i.e, sort, field, argument, filter, relationship
Daniel Wehner
committed
* @param $override
* Override the actual handler object with this class. Used for
* aggregation when the handler is redirected to the aggregation
* handler.
The Great Git Migration
committed
*
* @return
* An instance of a handler object. May be views_handler_broken.
*/
Daniel Wehner
committed
function views_get_handler($table, $field, $key, $override = NULL) {
Daniel Wehner
committed
static $recursion_protection = array();
The Great Git Migration
committed
$data = views_fetch_data($table);
Daniel Wehner
committed
$handler = NULL;
The Great Git Migration
committed
if (isset($data[$field][$key])) {
Daniel Wehner
committed
// Support old views_data entries conversion.
if (isset($data[$field][$key]['moved to'])) {
list($moved_table, $moved_field) = $data[$field][$key]['moved to'];
if (!empty($recursion_protection[$moved_table][$moved_field])) {
// recursion detected!
return NULL;
}
$recursion_protection[$moved_table][$moved_field] = TRUE;
$handler = views_get_handler($moved_table, $moved_field, $key, $override);
$recursion_protection = array();
if ($handler) {
// store these values so we know what we were originally called.
$handler->original_table = $table;
$handler->original_field = $field;
if (empty($handler->actual_table)) {
$handler->actual_table = $moved_table;
$handler->actual_field = $moved_field;
}
}
return $handler;
}
The Great Git Migration
committed
// Set up a default handler:
if (empty($data[$field][$key]['handler'])) {
$data[$field][$key]['handler'] = 'views_handler_' . $key;
}
Daniel Wehner
committed
if ($override) {
$data[$field][$key]['override handler'] = $override;
}
$handler = _views_prepare_handler($data[$field][$key], $data, $field, $key);
The Great Git Migration
committed
}
Daniel Wehner
committed
if ($handler) {
return $handler;
}
The Great Git Migration
committed
// DEBUG -- identify missing handlers
Daniel Wehner
committed
vpr("Missing handler: $table $field $key");
The Great Git Migration
committed
$broken = array(
'title' => t('Broken handler @table.@field', array('@table' => $table, '@field' => $field)),
'handler' => 'views_handler_' . $key . '_broken',
'table' => $table,
'field' => $field,
);
return _views_create_handler($broken, 'handler', $key);
The Great Git Migration
committed
}
/**
* Fetch Views' data from the cache
*/
Daniel Wehner
committed
function views_fetch_data($table = NULL, $reset = FALSE) {
The Great Git Migration
committed
views_include('cache');
Daniel Wehner
committed
return _views_fetch_data($table, $reset);
The Great Git Migration
committed
}
// -----------------------------------------------------------------------
// Views plugin functions
/**
* Fetch the plugin data from cache.
*/
Daniel Wehner
committed
function views_fetch_plugin_data($type = NULL, $plugin = NULL, $reset = FALSE) {
The Great Git Migration
committed
views_include('cache');
Daniel Wehner
committed
return _views_fetch_plugin_data($type, $plugin, $reset);
The Great Git Migration
committed
}
/**
* Get a handler for a plugin
*/
Daniel Wehner
committed
function views_get_plugin($type, $plugin, $reset = FALSE) {
views_include('handlers');
Daniel Wehner
committed
$definition = views_fetch_plugin_data($type, $plugin, $reset);
The Great Git Migration
committed
if (!empty($definition)) {
return _views_create_handler($definition, $type);
}
}
// -----------------------------------------------------------------------
// 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, $reset = FALSE) {
The Great Git Migration
committed
$null = NULL;
// Attempt to load individually cached view from cache.
views_include('cache');
if (!$reset) {
$data = views_cache_get("views_default:{$view_name}", TRUE);
if (isset($data->data) && is_object($data->data)) {
return $data->data;
}
}
// Otherwise, allow entire cache to be rebuilt.
$cache = views_discover_default_views($reset);
The Great Git Migration
committed
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
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($reset = FALSE) {
The Great Git Migration
committed
static $cache = array();
if (empty($cache) || $reset) {
The Great Git Migration
committed
views_include('cache');
$cache = _views_discover_default_views($reset);
The Great Git Migration
committed
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
}
return $cache;
}
/**
* 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) {
// @todo: Use a smarter flagging system so that we don't have to
// load every view for this.
$result = array();
$views = views_get_all_views();
foreach ($views as $view) {
// Skip disabled views.
if (!empty($view->disabled)) {
continue;
}
if (empty($view->display)) {
// Skip this view as it is broken.
vsm(t("Skipping broken view @view", array('@view' => $view->name)));
continue;
}
// Loop on array keys because something seems to muck with $view->display
// a bit in PHP4.