| 1 |
<?php |
<?php |
| 2 |
// $Id: views.module,v 1.193 2007/08/12 06:52:14 merlinofchaos Exp $ |
// $Id: views.module,v 1.194 2007/08/19 23:29:50 merlinofchaos Exp $ |
| 3 |
|
|
| 4 |
/** |
/** |
| 5 |
* @file views.module |
* @file views.module |
| 7 |
*/ |
*/ |
| 8 |
|
|
| 9 |
/** |
/** |
| 10 |
* Implementation of hook_menu |
* Register views theming functions. |
| 11 |
*/ |
*/ |
| 12 |
function views_menu() { |
function views_theme() { |
| 13 |
$items['views/test'] = array( |
$path = drupal_get_path('module', 'views'); |
| 14 |
'page callback' => 'views_test', |
include_once "$path/theme/theme.inc"; |
| 15 |
'access callback' => TRUE, |
|
| 16 |
'title' => 'Views test', |
// Some quasi clever array merging here. |
| 17 |
'type' => MENU_NORMAL_ITEM, |
$base = array( |
| 18 |
|
// 'file' => 'theme.inc', |
| 19 |
|
'path' => "$path/theme", |
| 20 |
); |
); |
|
$items['views/test/1'] = array( |
|
|
'page callback' => 'views_test_1', |
|
|
'access callback' => TRUE, |
|
|
'title' => 'Views test 1', |
|
|
'type' => MENU_NORMAL_ITEM, |
|
|
); |
|
|
$items['views/test/2'] = array( |
|
|
'page callback' => 'views_test_2', |
|
|
'access callback' => TRUE, |
|
|
'title' => 'Views test 2', |
|
|
'type' => MENU_NORMAL_ITEM, |
|
|
); |
|
|
|
|
|
|
|
|
return $items; |
|
|
} |
|
|
|
|
|
|
|
|
function views_test() { |
|
|
views_include_view(); |
|
|
views_include_query(); |
|
|
|
|
|
$output = ''; |
|
|
|
|
|
$view = views_get_view('views_test'); |
|
|
if (!$view) { |
|
|
$view = new view; |
|
|
$view->name = 'views_test'; |
|
|
$view->description = 'A view being used to test some handlers.'; |
|
|
$view->set_page_size(3); |
|
|
|
|
|
$field = new views_field; |
|
|
$field->table = 'node'; |
|
|
$field->field = 'title'; |
|
|
$view->field[] = drupal_clone($field); |
|
| 21 |
|
|
| 22 |
$field->field = 'created'; |
$arguments = array( |
| 23 |
$view->field[] = drupal_clone($field); |
'display' => array('view' => NULL), |
| 24 |
|
'style' => array('view' => NULL, 'rows' => NULL), |
| 25 |
$field->table = 'users'; |
'row' => array('view' => NULL, 'row' => NULL), |
| 26 |
$field->field = 'name'; |
); |
|
$view->field[] = $field; |
|
|
|
|
|
$sort = new views_sort; |
|
|
$sort->table = 'node'; |
|
|
$sort->field = 'created'; |
|
|
$sort->order = 'ASC'; |
|
|
$view->sort[] = $sort; |
|
| 27 |
|
|
| 28 |
/* |
// Default view themes |
| 29 |
$filter = new views_filter; |
$hooks['views_view'] = $base + array( |
| 30 |
$filter->table = 'node'; |
'file' => 'views-view', |
| 31 |
$filter->field = 'nid'; |
// 'template' => 'views-view', |
| 32 |
$filter->operator = '='; |
'pattern' => 'views_view__', |
| 33 |
$filter->value = 3; |
'arguments' => $arguments['display'], |
| 34 |
$view->filter[] = $filter; |
); |
| 35 |
*/ |
$hooks['views_view_rows'] = $base + array( |
| 36 |
|
'file' => 'views-view-rows', |
| 37 |
|
// 'template' => 'views-view-rows', |
| 38 |
|
'pattern' => 'views_view_rows__', |
| 39 |
|
'arguments' => $arguments['style'], |
| 40 |
|
); |
| 41 |
|
$hooks['views_view_row'] = $base + array( |
| 42 |
|
'file' => 'views-view-row', |
| 43 |
|
// 'template' => 'views-view-row', |
| 44 |
|
'pattern' => 'views_view_row__', |
| 45 |
|
'arguments' => $arguments['row'], |
| 46 |
|
); |
| 47 |
|
$hooks['views_view_field'] = $base + array( |
| 48 |
|
'pattern' => 'views_view_field__', |
| 49 |
|
'arguments' => array('view' => NULL, 'field' => NULL, 'row' => NULL), |
| 50 |
|
); |
| 51 |
|
|
| 52 |
$argument = new views_argument; |
$plugins = views_fetch_plugin_data(); |
|
$argument->table = 'node'; |
|
|
$argument->field = 'nid'; |
|
|
$argument->default_action = 'summary asc'; |
|
|
$view->argument[] = $argument; |
|
| 53 |
|
|
| 54 |
$view->save(); |
// Register theme functions for all style plugins |
| 55 |
|
foreach ($plugins as $type => $info) { |
| 56 |
|
foreach ($info as $plugin => $def) { |
| 57 |
|
if (isset($def['theme'])) { |
| 58 |
|
$hooks[$def['theme']] = array( |
| 59 |
|
'pattern' => $def['theme'] . '__', |
| 60 |
|
// 'file' => $def['file'], |
| 61 |
|
'path' => $def['path'], |
| 62 |
|
'arguments' => $arguments[$type], |
| 63 |
|
); |
| 64 |
|
if (!function_exists('theme_' . $def['theme'])) { |
| 65 |
|
$hooks[$def['theme']]['file'] = views_css_safe($def['theme']); |
| 66 |
|
// $hooks[$def['theme']]['template'] = views_css_safe($def['theme']); |
| 67 |
|
} |
| 68 |
|
} |
| 69 |
|
} |
| 70 |
} |
} |
| 71 |
|
|
| 72 |
$view->build(); |
return $hooks; |
|
$view2 = views_get_view('views_test'); |
|
|
$view2->args = array('1'); |
|
|
$view2->build(); |
|
|
$output = '<pre>'; |
|
|
$output .= print_r($view->build_info, 1); |
|
|
$output .= print_r($view2->build_info, 1); |
|
|
$output .= '</pre>'; |
|
|
return $output; |
|
| 73 |
} |
} |
| 74 |
|
|
| 75 |
|
/** |
| 76 |
|
* Include views .inc files as necessary. |
| 77 |
|
*/ |
| 78 |
|
function views_include($file) { |
| 79 |
|
require_once drupal_get_path('module', 'views') . "/includes/$file.inc"; |
| 80 |
|
} |
| 81 |
|
|
| 82 |
function views_test_1() { |
/** |
| 83 |
views_include_view(); |
* Load views files on behalf of modules. |
| 84 |
|
*/ |
| 85 |
$view = new view; |
function views_include_handlers() { |
| 86 |
$view->name = 'foo'; |
static $finished = FALSE; |
| 87 |
$view->description = 'foobar'; |
// Ensure this only gets run once. |
| 88 |
$view->set_page_size(3); |
if ($finished) { |
| 89 |
|
return; |
| 90 |
$argument = new views_argument; |
} |
|
$argument->type = 'node_nid'; |
|
|
$argument->default_action = 'not_found'; |
|
|
$argument->title = '%1'; |
|
|
|
|
|
$view->argument[] = drupal_clone($argument); |
|
|
$argument->default_action = 'summary, ascended'; |
|
|
$view->argument[] = $argument; |
|
|
|
|
|
$view->save(); |
|
|
|
|
|
$view2 = new view; |
|
|
$view2->load($view->vid); |
|
| 91 |
|
|
| 92 |
$output = '<pre>'; |
views_include('handlers'); |
| 93 |
$array = array(); |
$views_path = drupal_get_path('module', 'views') . '/modules'; |
| 94 |
$output .= "Array test: " . (array_push($array, 'foo')); |
foreach (module_list() as $module) { |
| 95 |
$output .= "\n"; |
$module_path = drupal_get_path('module', $module); |
| 96 |
$output .= var_export($view, 1); |
if (file_exists("$module_path/$module.views.inc")) { |
| 97 |
$output .= var_export($view2, 1); |
include_once "$module_path/$module.views.inc"; |
| 98 |
$output .= '</pre>'; |
} |
| 99 |
return $output; |
else if (file_exists("$views_path/$module.views.inc")) { |
| 100 |
|
include_once "$views_path/$module.views.inc"; |
| 101 |
|
} |
| 102 |
|
} |
| 103 |
|
$finished = TRUE; |
| 104 |
} |
} |
| 105 |
|
|
| 106 |
function views_test_2() { |
/** |
| 107 |
|
* Fetch Views' data from the cache |
| 108 |
views_include_query(); |
*/ |
| 109 |
$query = new views_query; |
function views_fetch_data($table = NULL) { |
| 110 |
|
static $cache = NULL; |
| 111 |
|
if (!isset($cache)) { |
| 112 |
|
$start = microtime(); |
| 113 |
|
// NOTE: This happens whether we retrieve them from cache or otherwise. |
| 114 |
|
views_include_handlers(); |
| 115 |
|
$cache = module_invoke_all('views_data'); |
| 116 |
|
if (module_exists('devel')) { |
| 117 |
|
dsm('Views data build time: ' . (microtime() - $start) * 1000 . ' ms'); |
| 118 |
|
} |
| 119 |
|
} |
| 120 |
|
|
| 121 |
|
if (!$table) { |
| 122 |
|
return $cache; |
| 123 |
|
} |
| 124 |
|
if (isset($cache[$table])) { |
| 125 |
|
return $cache[$table]; |
| 126 |
|
} |
| 127 |
|
// Return an empty array if there is no match. |
| 128 |
|
return array(); |
| 129 |
|
} |
| 130 |
|
|
| 131 |
|
/** |
| 132 |
|
* Fetch a handler to join one table to a primary table from the data cache |
| 133 |
|
*/ |
| 134 |
|
function views_get_table_join($table, $primary_table) { |
| 135 |
|
$data = views_fetch_data($table); |
| 136 |
|
if (isset($data['table']['join'][$primary_table])) { |
| 137 |
|
$h = $data['table']['join'][$primary_table]; |
| 138 |
|
$handler = new $h['handler']; |
| 139 |
|
if (isset($h['arguments'])) { |
| 140 |
|
call_user_func_array(array($handler, 'construct'), $h['arguments']); |
| 141 |
|
} |
| 142 |
|
return $handler; |
| 143 |
|
} |
| 144 |
|
// DEBUG -- identify missing handlers |
| 145 |
|
dsm("join: $table $primary_table"); |
| 146 |
|
} |
| 147 |
|
|
| 148 |
$book_parent = $query->add_relationship('book_parent', new views_join('node', 'book', 'pid', 'nid')); |
/** |
| 149 |
$book_parent_users = $query->ensure_table('users', 'book_parent'); |
* Instantiate and construct a new handler |
| 150 |
|
*/ |
| 151 |
|
function _views_create_handler($definition) { |
| 152 |
|
// dpr('Instantiating handler ' . $definition['handler']); |
| 153 |
|
$handler = new $definition['handler']; |
| 154 |
|
if (isset($definition['arguments'])) { |
| 155 |
|
call_user_func_array(array($handler, 'construct'), $definition['arguments']); |
| 156 |
|
} |
| 157 |
|
|
| 158 |
$book_parent_parent = $query->add_relationship('book_parent_parent', new views_join('node', 'book', 'pid', 'nid'), 'book_parent'); |
$handler->set_definition($definition); |
| 159 |
$book_parent_parent_users = $query->ensure_table('users', 'book_parent_parent'); |
return $handler; |
| 160 |
|
} |
| 161 |
|
|
| 162 |
|
/** |
| 163 |
|
* Prepare a handler's data by checking defaults and such. |
| 164 |
|
*/ |
| 165 |
|
function _views_prepare_handler($definition, $data, $field) { |
| 166 |
|
foreach (array('group', 'title', 'help') as $key) { |
| 167 |
|
// First check the field level |
| 168 |
|
if (!isset($definition[$key]) && !empty($data[$field][$key])) { |
| 169 |
|
$definition[$key] = $data[$field][$key]; |
| 170 |
|
} |
| 171 |
|
// Then if that doesn't work, check the table level |
| 172 |
|
if (!isset($definition['table'][$key]) && !empty($data['table'][$key])) { |
| 173 |
|
$definition[$key] = $data['table'][$key]; |
| 174 |
|
} |
| 175 |
|
} |
| 176 |
|
|
| 177 |
|
return _views_create_handler($definition); |
| 178 |
|
} |
| 179 |
|
|
| 180 |
$query->add_relationship('term_hierarchy_1', new views_join('term_hierarchy', 'term_hierarchy', 'parent', 'tid')); |
/** |
| 181 |
$query->add_relationship('term_hierarchy_2', new views_join('term_hierarchy', 'term_hierarchy', 'parent', 'tid'), 'term_hierarchy_1'); |
* Fetch a handler from the data cache. |
| 182 |
$book_parent_users = $query->ensure_table('term_data'); |
*/ |
| 183 |
$book_parent_users = $query->ensure_table('term_data', 'term_hierarchy_1', new views_join('term_data', 'term_hierarchy', 'tid', 'tid')); |
function views_get_handler($table, $field, $key) { |
| 184 |
$book_parent_users = $query->ensure_table('term_data_x', 'term_hierarchy_2'); |
$data = views_fetch_data($table); |
| 185 |
|
if (isset($data[$field][$key])) { |
| 186 |
|
return _views_prepare_handler($data[$field][$key], $data, $field); |
| 187 |
|
} |
| 188 |
|
// DEBUG -- identify missing handlers |
| 189 |
|
dsm("$table $field $key"); |
| 190 |
|
} |
| 191 |
|
|
| 192 |
$query->add_field('bar', 'baz'); |
function views_discover_plugins() { |
| 193 |
$query->add_field('node', 'title'); |
$cache = array('display' => array(), 'style' => array(), 'row' => array()); |
| 194 |
$query->add_field(NULL, 'unix_timestamp(some_value)'); |
// Get plugins from all mdoules. |
| 195 |
|
foreach (module_implements('views_plugins') as $module) { |
| 196 |
|
$function = $module . '_views_plugins'; |
| 197 |
|
$result = $function(); |
| 198 |
|
if (!is_array($result)) { |
| 199 |
|
continue; |
| 200 |
|
} |
| 201 |
|
// Setup automatic path/file finding for theme registration |
| 202 |
|
if (isset($result['module']) && $result['module'] == 'views') { |
| 203 |
|
$path = drupal_get_path('module', $module) . '/theme'; |
| 204 |
|
$file = 'theme.inc'; |
| 205 |
|
} |
| 206 |
|
else { |
| 207 |
|
$path = drupal_get_path('module', $module); |
| 208 |
|
$file = "$module.views.inc"; |
| 209 |
|
} |
| 210 |
|
foreach ($result as $type => $info) { |
| 211 |
|
if ($type == 'module') { |
| 212 |
|
continue; |
| 213 |
|
} |
| 214 |
|
foreach ($info as $plugin => $def) { |
| 215 |
|
if (isset($def['theme']) && !isset($def['path'])) { |
| 216 |
|
$def['path'] = $path; |
| 217 |
|
$def['file'] = $file; |
| 218 |
|
} |
| 219 |
|
// merge the new data in |
| 220 |
|
$cache[$type][$plugin] = $def; |
| 221 |
|
} |
| 222 |
|
} |
| 223 |
|
} |
| 224 |
|
return $cache; |
| 225 |
|
} |
| 226 |
|
|
| 227 |
$query->set_where_group('or', 'or'); |
/** |
| 228 |
$query->add_where(0, 'froot_loops = 1', 'froot', 'loops'); |
* Fetch the plugin data from cache. |
| 229 |
$query->add_where(0, 'gay = yes', 'gay', 'yes'); |
*/ |
| 230 |
$query->add_where('or', 'foo = bar'); |
function views_fetch_plugin_data($type = NULL, $plugin = NULL) { |
| 231 |
$query->add_where('or', 'bar = baz', 'bar', 'baz'); |
static $cache = NULL; |
| 232 |
|
if (!isset($cache)) { |
| 233 |
|
$start = microtime(); |
| 234 |
|
views_include('plugins'); |
| 235 |
|
views_include_handlers(); |
| 236 |
|
|
| 237 |
|
$cache = views_discover_plugins(); |
| 238 |
|
|
| 239 |
|
if (module_exists('devel')) { |
| 240 |
|
dsm('Views plugins build time: ' . (microtime() - $start) * 1000 . ' ms'); |
| 241 |
|
} |
| 242 |
|
} |
| 243 |
|
|
| 244 |
$output = ''; |
if (!$type && !$plugin) { |
| 245 |
|
return $cache; |
| 246 |
|
} |
| 247 |
|
else if (!$plugin) { |
| 248 |
|
// Not in the if above so the else below won't run |
| 249 |
|
if (isset($cache[$type])) { |
| 250 |
|
return $cache[$type]; |
| 251 |
|
} |
| 252 |
|
} |
| 253 |
|
else if (isset($cache[$type][$plugin])) { |
| 254 |
|
return $cache[$type][$plugin]; |
| 255 |
|
} |
| 256 |
|
|
| 257 |
$output .= '<pre>'; |
// Return an empty array if there is no match. |
| 258 |
$output .= $query->query() . "\n"; |
return array(); |
|
$output .= var_export($query->get_where_args(), true) . "\n"; |
|
|
/* |
|
|
$output .= "book_parent: <b>$book_parent</b>\n"; |
|
|
$output .= "book_parent_users: <b>$book_parent_users</b>\n"; |
|
|
$output .= "book_parent_parent: <b>$book_parent_parent</b>\n"; |
|
|
$output .= "book_parent_parent_users: <b>$book_parent_parent_users</b>\n"; |
|
|
*/ |
|
|
$output .= var_export($query, 1); |
|
|
$output .= '</pre>'; |
|
|
return $output; |
|
| 259 |
} |
} |
| 260 |
|
|
| 261 |
/** |
/** |
| 262 |
* Include view.inc |
* Get a handler for a plugin |
| 263 |
*/ |
*/ |
| 264 |
function views_include_view() { |
function views_get_plugin($type, $plugin) { |
| 265 |
require_once drupal_get_path('module', 'views') . '/includes/view.inc'; |
$definition = views_fetch_plugin_data($type, $plugin); |
| 266 |
|
if (!empty($definition)) { |
| 267 |
|
return _views_create_handler($definition); |
| 268 |
|
} |
| 269 |
} |
} |
| 270 |
|
|
| 271 |
/** |
/** |
| 272 |
* Include query.inc |
* Prepare the specified string for use as a CSS identifier. |
| 273 |
*/ |
*/ |
| 274 |
function views_include_query() { |
function views_css_safe($string) { |
| 275 |
views_include_handlers(); |
return str_replace('_', '-', $string); |
|
require_once drupal_get_path('module', 'views') . '/includes/query.inc'; |
|
| 276 |
} |
} |
| 277 |
|
|
| 278 |
/** |
/** |
| 279 |
* Include handlers.inc |
* Basic definition for many views objects |
| 280 |
*/ |
*/ |
| 281 |
function views_include_handlers() { |
class views_object { |
| 282 |
require_once drupal_get_path('module', 'views') . '/includes/handlers.inc'; |
/** |
| 283 |
} |
* Views handlers use a special construct function so that we can more |
| 284 |
|
* easily construct them with variable arguments. |
| 285 |
// STUB FUNCTION -- temporary data so there's something to test with. |
*/ |
| 286 |
function views_get_table_join($table, $primary_table) { |
function construct() { } |
| 287 |
// temp hack |
|
| 288 |
static $cache = array(); |
/** |
| 289 |
if (empty($cache)) { |
* Let the handler know what its full definition is. |
| 290 |
$cache['users'] = new views_join('users', 'node', 'uid', 'uid'); |
*/ |
| 291 |
$cache['term_node'] = new views_join('term_node', 'node', 'nid', 'nid'); |
function set_definition($definition) { |
| 292 |
$cache['term_data'] = new views_join('term_data', 'term_node', 'tid', 'tid'); |
$this->definition = $definition; |
| 293 |
$cache['term_data_x'] = new views_join('term_data', 'term_hierarchy', 'tid', 'tid'); |
if (isset($definition['field'])) { |
| 294 |
$cache['term_hierarchy'] = new views_join('term_hierachy', 'term_node', 'tid', 'tid'); |
$this->real_field = $definition['field']; |
| 295 |
$cache['book'] = new views_join('book', 'node', 'nid', 'nid'); |
} |
|
$cache['foo'] = new views_join('foo', 'node', 'nid', 'nid'); |
|
|
$cache['bar'] = new views_join('bar', 'foo', 'baz', 'baz'); |
|
|
} |
|
|
|
|
|
// if ($table == 'node') { drupal_set_message('<pre>'.var_export(debug_backtrace(), 1)); } |
|
|
return $cache[$table]; |
|
|
} |
|
|
|
|
|
// STUB FUNCTION -- temporary data so there's something to test with. |
|
|
function views_get_handler($table, $field, $key) { |
|
|
switch ($key) { |
|
|
case 'field': |
|
|
switch ($field) { |
|
|
case 'title': |
|
|
return new views_handler_field(TRUE); |
|
|
case 'name': |
|
|
return new views_handler_field(TRUE); |
|
|
case 'created': |
|
|
return new views_handler_field_date(TRUE); |
|
|
} |
|
|
break; |
|
|
case 'sort': |
|
|
switch ($field) { |
|
|
case 'created': |
|
|
return new views_handler_sort(); |
|
|
} |
|
|
break; |
|
|
case 'filter': |
|
|
switch ($field) { |
|
|
case 'nid': |
|
|
return new views_handler_filter(); |
|
|
} |
|
|
break; |
|
|
case 'argument': |
|
|
return new views_handler_argument('title'); |
|
| 296 |
} |
} |
| 297 |
} |
} |