Commit b06399e3 authored by merlinofchaos's avatar merlinofchaos

Basic menu code (needs patch to core). Maybe basic block code too, but I didn't test that part.

parent 4291d390
......@@ -202,6 +202,7 @@ class views_handler_relationship extends views_handler {
* Base field handler that has no options and renders an unformatted field.
*/
class views_handler_field extends views_handler {
var $field_alias = 'unknown';
/**
* Construct a new field handler.
......@@ -218,7 +219,7 @@ class views_handler_field extends views_handler {
$this->ensure_my_table();
// Add the field.
$this->field_alias = $this->query->add_field($this->table_alias, $this->real_field);
dpr("alias: $this->field_alias");
// Add any additional fields we are given.
if (!empty($this->additional_fields) && is_array($this->additional_fields)) {
foreach ($this->additional_fields as $field) {
......@@ -591,6 +592,13 @@ class views_handler_argument extends views_handler {
function title() {
return check_plain($this->argument);
}
/**
* Validate that this argument works. By default, all arguments are valid.
*/
function validate($arg) {
return TRUE;
}
}
/**
......
......@@ -17,11 +17,13 @@ function views_views_plugins() {
'title' => t('Page'),
'help' => t('Creates a page with a URL, menu links, etc.'),
'handler' => 'views_display_plugin_page',
'uses_hook_menu' => TRUE,
),
'block' => array(
'title' => t('Block'),
'help' => t('Creates a block that can be used from the block administration page.'),
'handler' => 'views_display_plugin_block',
'title' => t('Block'),
'help' => t('Creates a block that can be used from the block administration page.'),
'handler' => 'views_display_plugin_block',
'uses_hook_block' => TRUE,
),
'embed' => array(
'title' => t('Embedded'),
......@@ -127,35 +129,51 @@ class views_display_plugin extends views_object {
function render_more_link() { }
/**
* Not all display plugins will have a feed icon, nor will they
* put it in the same place.
* Not all display plugins will have a feed icon.
*/
function render_feed_icon() { }
/**
* Render the view's title for display
* TODO: Necessary? Hm.
*/
function render_title() { }
function render_header() { }
function render_footer() { }
function render_empty() { return 'empty text'; }
function render_textarea($area) {
$format_string = $area . '_format';
return check_markup($this->display->$area, $this->display->$format_string);
}
/**
* Render the header of the view.
*/
function render_header() { return $this->render_textarea('header'); }
/**
* Render the footer of the view.
*/
function render_footer() { return $this->render_textarea('footer'); }
/**
* Render the empty text of the view.
*/
function render_empty() { return $this->render_textarea('empty'); }
/**
* If this display creates a block, implement one of these.
*/
// function hook_block($op = 'list', $delta = 0, $edit = array()) {}
function hook_block($op = 'list', $delta = 0, $edit = array()) { return array(); }
/**
* If this display creates a page with a menu item, implement it here.
*/
// function hook_menu() {}
function hook_menu() { return array(); }
/**
* Render this display.
*/
function render() {
// TODO: Remove this when the 'file' tag on theme registry is fixed.
include_once drupal_get_path('module', 'views') . '/theme/theme.inc';
// include_once drupal_get_path('module', 'views') . '/theme/theme.inc';
$themes = array(
'views_view__' . $this->display->id . '__' . $this->view->name,
'views_view__' . $this->display->id,
......@@ -167,6 +185,17 @@ class views_display_plugin extends views_object {
return theme($themes, $this->view);
}
/**
* Determine if the user has access to this display of the view.
*
* TODO: Implement this.
*/
function access($account) { return TRUE; }
/**
* When used externally, this is how a view gets run and returns
* data in the format required.
*/
function execute() { }
}
/**
......@@ -175,9 +204,43 @@ class views_display_plugin extends views_object {
class views_display_plugin_page extends views_display_plugin {
var $uses_hook_menu = TRUE;
function hook_menu() {}
function execute_hook_menu() {
$items = array();
// Replace % with the link to our standard views argument loader
// views_arg_load -- which lives in views.module
$url = str_replace('%', '%views_arg', $this->display->url);
function render_page() {}
// NOTE: This is the very simple 'menu normal item' version. The
// tab version needs to come later. Maybe it should be its own plugin.
$items[$url] = array(
// default views page entry
'page callback' => 'views_page',
'page arguments' => array($this->view->name, $this->display->id),
// Default access check (per display)
'access callback' => 'views_access',
'access arguments' => array(array($this->view->name, $this->display->id)),
// Identify URL embedded arguments and correlate them to a handler
'load arguments' => array($this->view->name, '%index'),
// Basic menu title
'title' => $this->display->title,
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
* The display page handler returns a normal view, but it also does
* a drupal_set_title for the page, and does a views_set_page_view
* on the view.
*/
function execute() {
views_set_page_view($this);
// Prior to this being called, the $view should already be set to this
// display, and arguments should be set on the view.
$this->view->build();
drupal_set_title(filter_xss_admin($this->view->get_title('page')));
return $this->view->render();
}
}
/**
......@@ -185,10 +248,30 @@ class views_display_plugin_page extends views_display_plugin {
*/
class views_display_plugin_block extends views_display_plugin {
var $uses_hook_block = TRUE;
/**
* If this display creates a block, implement one of these.
* The default block handler doesn't support configurable items,
* but extended block handlers might be able to do interesting
* stuff with it.
*/
function hook_block($op = 'list', $delta = 0, $edit = array()) {
if ($op == 'list') {
$delta = $this->view->name . '-' . $this->display->id;
return array($delta => array('info' => $this->display->block_description));
}
}
/**
* The display block handler returns the structure necessary for a block.
*/
function hook_block($op = 'list', $delta = 0, $edit = array()) {}
function execute() {
drupal_set_page_view($this);
// Prior to this being called, the $view should already be set to this
// display, and arguments should be set on the view.
$info['content'] = $this->view->render();
$info['subject'] = filter_xss_admin($this->view->get_title('page'));
return $info;
}
}
/**
......@@ -230,7 +313,13 @@ class views_style_plugin_default extends views_style_plugin {
// provide an option form to select from our list of node renderers
}
/**
* Render the given style.
*/
function render() {
// TODO: This needs to be able to support either a database resource OR
// an array, because our input format doesn't actually have to be from
// a query.
$plugin = new views_row_plugin;
$rows = '';
while ($row = db_fetch_object($this->view->result)) {
......
......@@ -32,7 +32,7 @@ class view extends views_db_object {
var $page_size = 25;
var $pager_element = 0;
var $offset = 0;
var $current_page = 0;
/**
* Constructor
*/
......@@ -63,7 +63,7 @@ class view extends views_db_object {
* Set the arguments that come to this view. Usually from the URL
* but possibly from elsewhere.
*/
function set_args($args) {
function set_arguments($args) {
$this->args = $args;
}
......@@ -192,7 +192,7 @@ class view extends views_db_object {
}
// Execute the initial PHP code that a view can have.
if ($this->view_args_php) {
if (!empty($this->view_args_php)) {
ob_start();
$result = eval($this->view_args_php);
if (is_array($result)) {
......@@ -211,6 +211,7 @@ class view extends views_db_object {
$views_data = views_fetch_data($this->base_table);
$this->base_field = $views_data['table']['base']['field'];
views_include('query');
$this->query = new views_query($this->base_table, $this->base_field);
// Call a module hook and see if it wants to present us with a
......@@ -219,7 +220,7 @@ class view extends views_db_object {
// TODO: Implement this.
// Run through our handlers and ensure they have necessary information.
$this->_seed_handlers();
$this->seed_handlers();
// Build all the filters.
$this->_build('filter');
......@@ -237,7 +238,7 @@ class view extends views_db_object {
continue;
}
if (isset($this->args[$id])) {
if (isset($this->args[$id]) && $argument->handler->validate($this->args[$id])) {
// handle argument that is present.
// TODO: Do we want to put in argument placeholders here
// So that we can try to cache queries with arguments too?
......@@ -257,6 +258,9 @@ class view extends views_db_object {
}
}
// TODO: if $argument_title is set, get the argument and
// set it in the build info.
// Build our sort criteria if we were instructed to do so.
if (!empty($this->build_sort)) {
$this->_build('sort');
......@@ -290,7 +294,7 @@ class view extends views_db_object {
/**
* Acquire and attach all of the handlers.
*/
function _seed_handlers() {
function seed_handlers() {
if (empty($this->seeded)) {
foreach ($this->objects() as $key) {
$this->_seed_handler($key);
......@@ -374,6 +378,51 @@ class view extends views_db_object {
return $this->display_handler->render();
}
/**
* To be called externally. Execute the given display, with
* the given arguments.
*/
function execute_display($display_id = NULL, $args = array()) {
// Prepare the view with the information we have.
$this->set_arguments($args);
$this->set_display($display_id);
// Execute the view
if (isset($this->display_handler)) {
return $this->display_handler->execute();
}
}
/**
* Called to get hook_menu information from the view and the
* named display handler.
*/
function execute_hook_menu($display_id = NULL) {
// Prepare the view with the information we have.
$this->set_display($display_id);
// Execute the view
if (isset($this->display_handler)) {
return $this->display_handler->execute_hook_menu();
}
}
/**
* Determine if the given user has access to the view. Note that
* this sets the display handler if it hasn't been.
*/
function access($account) {
if (empty($this->display_handler) && !$this->set_display()) {
return FALSE;
}
if (!$account) {
$account = $GLOBALS['user'];
}
return $this->display_handler->access($account);
}
/**
* Get the view's current title. This can change depending upon how it
* was built.
......@@ -395,7 +444,8 @@ class view extends views_db_object {
/**
* Load a view from the database based upon either vid or name.
*/
function load($arg) {
function load($arg) {
// TODO: Move caching to here, make this a factory method.
$where = (is_numeric($arg) ? "vid = %d" : "name = '%s'");
$data = db_fetch_object(db_query("SELECT * FROM {views_view} WHERE $where", $arg));
if (empty($data)) {
......@@ -408,17 +458,52 @@ class view extends views_db_object {
foreach ($this->objects_all() as $key) {
$this->_load_row($key);
}
$view->loaded = TRUE;
$this->loaded = TRUE;
return TRUE;
}
/**
* Static factory method to load a list of views based upon a $where clause.
*/
function load_views($where, $join = '') {
// TODO: Integrate this in with caching.
$result = db_query("SELECT DISTINCT v.* FROM {views_view} v $join WHERE $where");
$views = array();
// Load all the views.
while ($data = db_fetch_object($result)) {
$view = new view;
$view->load_row($data);
$view->loaded = TRUE;
$views[$view->vid] = $view;
}
// Stop if we didn't get any views.
if (!$views) {
return array();
}
$vids = implode(', ', array_keys($views));
// Now load all the subtables:
foreach (view::objects_all() as $key) {
$object_name = "views_$key";
$result = db_query("SELECT * FROM {$object_name} WHERE vid IN ($vids) ORDER BY vid, position");
while ($data = db_fetch_object($result)) {
$object = new $object_name(FALSE);
$object->load_row($data);
array_push($views[$object->vid]->$key, $object);
}
}
return $views;
}
/**
* Load one of our sub tables.
*/
function _load_row($key) {
$object_name = "views_$key";
$table = $object_name;
$result = db_query("SELECT * FROM {$table} WHERE vid = %d ORDER BY position", $this->vid);
$result = db_query("SELECT * FROM {$object_name} WHERE vid = %d ORDER BY position", $this->vid);
while ($data = db_fetch_object($result)) {
$object = new $object_name(FALSE);
......
<?php
/**
* @file
* Provides views data and handlers for node.module
*/
function node_views_data() {
// Basic table information.
$data['node']['table'] = array(
......@@ -81,6 +85,8 @@ function node_views_data() {
/**
* Field handler to provide simple renderer that allows linking to a node.
*
* @ingroup views_field_handlers
*/
class views_handler_field_node extends views_handler_field {
/**
......@@ -124,6 +130,8 @@ class views_handler_field_node extends views_handler_field {
/**
* Field handler to translate a node type into its readable form.
*
* @ingroup views_field_handlers
*/
class views_handler_field_node_type extends views_handler_field_node {
function render($values) {
......
This diff is collapsed.
......@@ -48,7 +48,6 @@ function views_theme() {
$plugins = views_fetch_plugin_data();
// Register theme functions for all style plugins
foreach ($plugins as $type => $info) {
foreach ($info as $plugin => $def) {
......@@ -69,6 +68,134 @@ function views_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 ($view = views_get_view($name)) {
$view->seed_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 ($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();
}
/**
* 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 ($view = views_get_view($name)) {
if ($op == 'view') {
return $view->execute_display($display_id, $args);
}
else {
return $view->execute_hook_block($display_id, $op, $delta, $edit);
}
}
break;
}
}
/**
* Determine if the given user has access to the view + display.
*/
function views_access($view, $account = NULL) {
if (is_array($view)) {
list($name, $display_id) = $view;
$view = views_get_view($name);
if (!$view) {
return FALSE;
}
$view->set_display($display_id);
}
if (is_string($view)) {
$view = views_get_view($name);
if (!$view) {
return FALSE;
}
}
return $view->access($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();
}
/**
* Include views .inc files as necessary.
*/
......@@ -298,12 +425,82 @@ class views_object {
*
* @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) {
static $cache = array();
if (!array_key_exists($name, $cache)) {
// Ensure we at least have a NULL.
$cache[$name] = NULL;
views_include('view');
$view = new view;
if ($view->load($name)) {
$cache[$name] = $view;
}
// TODO: check for default views in cache.
}
return $cache[$name];
}
/**
* 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),
* );
*/
function views_get_page_views() {
// First, get all applicable views.
views_include('view');
$views = view::load_views("d.url IS NOT NULL AND d.url <> ''", "INNER JOIN {views_display} d ON v.vid = d.vid");
$result = array();
foreach ($views as $view) {
foreach ($view->display as $display) {
$plugin = views_fetch_plugin_data('display', $display->display_plugin);
if (!empty($plugin['uses_hook_menu'])) {
// 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);
$v->set_display($display->id);
$result[] = array($v, $display->id);
}
}
}
return $result;
}
/**
* 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.
*
* See @see views_get_page_views
*/
function views_get_view($name) {
function views_get_block_views() {
// First, get all applicable views.
views_include('view');
$view = new view;
if ($view->load($name)) {
return $view;
$views = view::load_views("d.block = 1", "INNER JOIN {views_display} d ON v.vid = d.vid");
$result = array();
foreach ($views as $view) {
$view->seed_handlers();
foreach ($view->display as $display) {
if ($display->handler && $display->handler->uses_hook_menu) {
$result[] = array($view, $display->id);
}
}
}
// TODO: check for default views in cache.
return $result;
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment