Commit cffc1056 authored by merlinofchaos's avatar merlinofchaos

First semi-working version of $view->render()!

parent 013538bb
This diff is collapsed.
<?php
// $Id$
/**
* @file Built in plugins for Views output handling.
*
*/
/**
* Implementation of hook_views_plugins
*/
function views_views_plugins() {
return array(
'module' => 'views', // This just tells our themes are elsewhere.
'display' => array(
'page' => array(
'title' => t('Page'),
'help' => t('Creates a page with a URL, menu links, etc.'),
'handler' => 'views_display_plugin_page',
),
'block' => array(
'title' => t('Block'),
'help' => t('Creates a block that can be used from the block administration page.'),
'handler' => 'views_display_plugin_block',
),
'embed' => array(
'title' => t('Embedded'),
'help' => t('Creates a view that is used from other code. By itself an embedded view does not do anything.'),
'handler' => 'views_display_plugin',
),
),
'style' => array(
'default' => array(
'title' => t('Default'),
'help' => t('Displays rows one after another.'),
'handler' => 'views_style_plugin_default',
'theme' => 'views_view_rows',
),
'list' => array(
'title' => t('List'),
'help' => t('Displays rows as an HTML list.'),
'handler' => 'views_style_plugin_list',
'theme' => 'views_view_list',
),
'table' => array(
'title' => t('Table'),
'help' => t('Displays rows in a table.'),
'handler' => 'views_style_plugin_table',
'theme' => 'views_view_table',
),
),
'row' => array(
'fields' => array(
'title' => t('Fields'),
'help' => t('Displays the fields with an optional template.'),
'handler' => 'views_row_plugin',
'theme' => 'views_view_row',
),
),
);
}
/**
* The default display plugin handler. Display plugins handle options and
* basic mechanisms for different output methods.
*
* -- hook_menu
* -- hook_menu
* -- render_page
*/
class views_display_plugin extends views_object {
var $uses_hook_block = FALSE;
var $uses_hook_menu = FALSE;
/**
* Fill this plugin in with the view, display, etc.
*/
function seed(&$view, $display) {
$this->view = $view;
$this->display = $display;
}
/**
* Intelligently get an option either from this display or from the
* default display, if directed to do so.
*/
function get_option($option) {
if (isset($this->display->display_options[$option])) {
return $this->display->display_options[$option];
}
if (empty($this->default_display)) {
return;
}
if (empty($this->display_options[$option . '_default'])) {
return;
}
if (isset($this->default_display->display_options[$option])) {
return $this->default_display->display_options[$option];
}
}
/**
* Provide the default form for setting options.
*/
function options_form(&$form) { }
/**
* Validate the options form.
*/
function options_validate($form, &$form_state) { }
/**
* Perform any necessary changes to the form values prior to storage.
* There is no need for this function to actually store the data.
*/
function options_submit($form, &$form_state) { }
/**
* Not all display plugins will support filtering
*/
function render_filters() { }
/**
* Not all display plugins will have a 'more' link
*/
function render_more_link() { }
/**
* Not all display plugins will have a feed icon, nor will they
* put it in the same place.
*/
function render_feed_icon() { }
/**
* Render the view's title for display
*/
function render_title() { }
function render_header() { }
function render_footer() { }
function render_empty() { return 'empty text'; }
/**
* If this display creates a block, implement one of these.
*/
// function hook_block($op = 'list', $delta = 0, $edit = array()) {}
/**
* If this display creates a page with a menu item, implement it here.
*/
// function hook_menu() {}
/**
* 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';
$themes = array(
'views_view__' . $this->display->id . '__' . $this->view->name,
'views_view__' . $this->display->id,
'views_view__' . $this->display->display_plugin . '__' . $this->view->name,
'views_view__' . $this->display->display_plugin,
'views_view__' . $this->view->name,
'views_view',
);
return theme($themes, $this->view);
}
}
/**
* The plugin that handles a full page.
*/
class views_display_plugin_page extends views_display_plugin {
var $uses_hook_menu = TRUE;
function hook_menu() {}
function render_page() {}
}
/**
* The plugin that handles a block.
*/
class views_display_plugin_block extends views_display_plugin {
var $uses_hook_block = TRUE;
/**
* If this display creates a block, implement one of these.
*/
function hook_block($op = 'list', $delta = 0, $edit = array()) {}
}
/**
* Base class to define a style plugin handler.
*/
class views_style_plugin extends views_object {
var $needs_fields = FALSE;
var $needs_headers = FALSE;
function seed(&$view, $display) {
$this->view = $view;
$this->display = $display;
$this->options = $display->style_options;
}
/**
* Provide a form for setting options.
*/
function options_form(&$form) { }
/**
* Validate the options form.
*/
function options_validate($form, &$form_state) { }
/**
* Perform any necessary changes to the form values prior to storage.
* There is no need for this function to actually store the data.
*/
function options_submit($form, &$form_state) { }
function render($rows) { }
}
class views_style_plugin_default extends views_style_plugin {
// TEMP HACK
var $row_plugin = 'views_row_plugin';
function options_form(&$form) {
// provide an option form to select from our list of node renderers
}
function render() {
$plugin = new views_row_plugin;
$rows = '';
while ($row = db_fetch_object($this->view->result)) {
$rows .= $plugin->render($this->view, $row);
}
return theme(array('views_view_rows__' . $this->view->name, 'views_view_rows'), $this->view, $rows);
}
}
/**
* Default plugin to view a single row of a table. This is really just a wrapper around
* a theme function.
*/
class views_row_plugin extends views_object {
function render(&$view, $row) {
return theme(array('views_view_row__' . $view->name, 'views_view_row'), $view, $row);
}
}
......@@ -77,52 +77,159 @@ class view {
$this->offset = $offset;
}
/**
* Set the exposed filters input to an array. If unset they will be taken
* from $_GET when the time comes.
*/
function set_filter_input($filters) {
$this->filter_input = $filters;
}
function set_display($display_id) {
$this->display = $display_id;
function get_fields($display_id = NULL) {
if (!isset($display_id)) {
$display_id = $this->current_display;
}
// TODO: Fix this:
return $this->field;
}
/**
* Set the display for this view, and initialize the display handler.
*/
function set_display($display_id = NULL) {
// The default display is always the first one in the list.
if (isset($this->current_display)) {
return TRUE;
}
$this->default_display = 0;
if (!isset($display_id)) {
$this->current_display = 0;
}
foreach ($this->display as $id => $display) {
if ($display->id == $display_id) {
$this->current_display = $id;
}
}
// If the id was invalid, then just use the default display.
if (!isset($this->current_display)) {
$this->current_display = 0;
}
if (!isset($this->display[$this->current_display])) {
return FALSE;
}
// Fetch the display handler data and instantiate an object.
$display_data = $this->display[$this->current_display];
$this->display_handler = views_get_plugin('display', $display_data->display_plugin);
if (empty($this->display_handler)) {
return FALSE;
}
// Seed the new display handler with data.
$this->display_handler->seed($this, $display_data);
// If this is NOT the default display handler, let it know which is
// since it may well utilize some data from the default.
if ($this->current_display != $this->default_display) {
$this->display_handler->default_display = $this->display[$this->default_display];
}
// Find and initialize the style plugin. Note that arguments may have changed
// which style plugin we use, so check the view object first, then ask
// the display handler.
if (!isset($this->style_plugin)) {
$this->style_plugin = $display_data->style_plugin;
}
$this->style_handler = views_get_plugin('style', $this->style_plugin);
if (empty($this->style_handler)) {
return FALSE;
}
// Seed the new display handler with data.
$this->style_handler->seed($this, $display_data);
return TRUE;
}
function build($display_id = NULL) {
if (!empty($this->built)) {
return;
}
$this->display_id = $display_id;
if (!$this->set_display($display_id)) {
return FALSE;
}
// Execute the initial PHP code that a view can have.
if ($this->view_args_php) {
ob_start();
$result = eval($this->view_args_php);
if (is_array($result)) {
$this->args = $result;
}
ob_end_clean();
}
// Attempt to load from cache.
// TODO: Load a build_info from cache.
// If that fails, let's build!
$this->build_info = array();
$views_data = views_fetch_data($this->base_table);
$this->base_field = $views_data['table']['base']['field'];
$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
// pre-built query or instruct us not to build the query for
// some reason.
// TODO: Implement this.
// If that fails, let's build!
$this->build_info = array();
$this->query = new views_query();
// Run through our handlers and ensure they have necessary information.
$this->_seed_handlers();
// Build all the filters.
$this->_build('filter');
$this->build_sort = $this->build_fields = TRUE;
$argument_title = '';
// build arguments.
foreach ($this->argument as $id => $argument) {
foreach ($this->argument as $id => $arg) {
unset ($argument);
$argument = &$this->argument[$id];
if (!is_object($argument->handler)) {
// TODO: Set some kind of warning.
continue;
}
if (isset($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?
$argument->handler->argument = $this->args[$id];
$argument->handler->query();
// Test to see if we should use this argument's title
if (!empty($argument->title)) {
$argument_title = $id;
}
}
else {
// determine default condition and handle.
$argument->handler->default_action();
if (!$argument->handler->default_action()) {
return;
}
}
}
......@@ -140,15 +247,20 @@ class view {
$this->build_info['count_query'] = $this->query->query(TRUE);
$this->build_info['query_args'] = $this->query->get_where_args();
$this->built = TRUE;
return TRUE;
}
/**
* Internal method to build an individual set of handlers.
*/
function _build($key) {
foreach ($this->$key as $data) {
$data->handler->query();
}
$array = &$this->$key;
foreach ($array as $id => $data) {
// TODO: we should report an error here if this is not an object.
if (is_object($array[$id]->handler)) {
$array[$id]->handler->query();
}
}
}
/**
......@@ -171,7 +283,7 @@ class view {
*/
function _seed_handler($key) {
foreach ($this->$key as $data) {
$handler = views_get_handler($data->table, $data->field, $key);
$handler = views_get_handler($data->tablename, $data->field, $key);
if (is_object($handler)) {
$handler->seed($this, $data);
$data->handler = $handler;
......@@ -179,20 +291,67 @@ class view {
}
}
/**
* Execute the view's query.
*/
function execute($display_id = NULL) {
if (!empty($this->executed)) {
return TRUE;
}
if (empty($this->built)) {
if (!$this->build($display_id)) {
return FALSE;
}
}
$query = db_rewrite_sql($this->build_info['query'], $this->base_table, $this->base_field);
$args = $this->build_info['query_args'];
// TODO: Fill in execution defaults if they are not set.
// use_pager, page_size, offset
$items = array();
if ($query) {
if (!empty($this->use_pager)) {
$count_query = db_rewrite_sql($this->build_info['count_query'], $this->base_table, $this->base_field);
$this->result = pager_query($query, $view->page_size, $view->use_pager - 1, $count_query, $args);
$this->total_rows = $GLOBALS['pager_total_items'][$this->use_pager - 1];
}
else if (!empty($this->page_size)) {
$offset = $this->current_page * $this->page_size + $this->offset;
$this->result = db_query_range($query, $args, $offset, $this->page_size);
}
else {
$this->result = db_query($query, $args);
}
}
$this->executed = TRUE;
}
/**
* Render this view for display.
*/
function render($display_id = NULL) {
if (empty($this->built)) {
$this->build($display_id);
// Check for cached output.
// TODO: Implement this
// Make sure the query has already executed.
if (empty($this->executed)) {
$this->execute($display_id);
}
// Check to see if the build failed.
if (empty($this->result)) {
return;
}
// Check for cached output.
return $this->display_handler->render();
}
function get_title($context) { }
function get_url() { }
function get_url($args = NULL) { }
function is_cacheable() { }
/**
......@@ -220,7 +379,7 @@ class view {
*/
function _load_row($key) {
$object_name = "views_$key";
$table = $object_name . 's';
$table = $object_name;
$result = db_query("SELECT * FROM {$table} WHERE vid = %d ORDER BY position", $this->vid);
while ($data = db_fetch_object($result)) {
......@@ -239,7 +398,7 @@ class view {
if (!empty($this->vid)) {
// remove existing table entries
foreach (views_objects_all() as $key) {
db_query("DELETE from {views_" . $key . "s} WHERE vid = %d", $this->vid);
db_query("DELETE from {views_" . $key . "} WHERE vid = %d", $this->vid);
$this->_load_row($key);
}
}
......@@ -263,7 +422,7 @@ class view {
foreach ($this->$key as $position => $object) {
$object->position = $position;
$object->vid = $this->vid;
_views_save_query("views_" . $key . "s", $object);
_views_save_query("views_" . $key, $object);
}
}
......@@ -278,7 +437,7 @@ class view {
db_query("DELETE FROM {views_view} WHERE vid = %d", $this->vid);
// Delete from all of our subtables as well.
foreach (views_objects_all() as $key) {
db_query("DELETE from {views_" . $key . "s} WHERE vid = %d", $this->vid);
db_query("DELETE from {views_" . $key . "} WHERE vid = %d", $this->vid);
$this->_load_row($key);
}
......
<?php
function node_views_data() {
// Basic table information.
$data['node']['table'] = array(
'group' => t('Node'), // Fields will default to this group
// Advertise this table as a possible base table
'base' => array(
'field' => 'nid',
'title' => t('Node'),
),
// For other base tables, explain how we join
'join' => array(
'users' => array(
'handler' => 'views_join', // this is actually optional
'arguments' => array('node', 'users', 'uid', 'uid'),
),
),
// Provide output plugins specifically for this base type.
'plugins' => array(
'node' => array(
'title' => t('Node'),
'help' => t('Display the node with standard node view.'),
'handler' => 'views_record_plugin_node_view',
),
),
);
// Fields
// title
$data['node']['title']['field'] = array(
'field' => 'title', // the real field
'group' => t('Node'), // The group it appears in on the UI,
'title' => t('Title'), // The item it appears as on the UI,
'help' => t('The title of the node'), // The help that appears on the UI,
'handler' => 'views_handler_field_node',
'arguments' => array(TRUE),
);
// nid
$data['node']['nid'] = array(
'title' => t('Nid'),
'help' => t('The node ID of the node'), // The help that appears on the UI,
'field' => array(
'handler' => 'views_handler_field_node',
'arguments' => array(TRUE),
),
'argument' => array(
'handler' => 'views_handler_argument',
'arguments' => array('title'),
),
'filter' => array(
'handler' => 'views_handler_filter',
),
);
// created field
$data['node']['created']['title'] = t('Post date'); // The item it appears as on the UI,
$data['node']['created']['help'] = t('The date the node was posted'); // The help that appears on the UI,
$data['node']['created']['field']['handler'] = 'views_handler_field_date';
$data['node']['created']['field']['arguments'] = array(TRUE);
$data['node']['created']['sort']['handler'] = 'views_handler_sort';
// changed field
$data['node']['changed']['field'] = array(
'title' => t('Updated date'), // The item it appears as on the UI,
'help' => t('The date the node was last updated'), // The help that appears on the UI,
'handler' => 'views_handler_field_date',
'arguments' => array(TRUE),
);
$data['node']['type']['field'] = array(
'title' => t('Type'), // The item it appears as on the UI,
'help' => t('The type of a node (for example, "blog entry", "forum post", "story", etc)'), // The help that appears on the UI,
'handler' => 'views_handler_field_node_type',
'arguments' => array(TRUE),
);
return $data;
}
/**
* Field handler to provide simple renderer that allows linking to a node.
*/
class views_handler_field_node extends views_handler_field {
/**
* Override seed function to provide generic option to link to node.
*/
function seed(&$view, &$data) {
parent::seed($view, $data);
if (isset($data->options['link_to_node']) && $view->base_table != 'node') {
$this->additional_fields[] = $nid;
$this->nid_field = 'node_nid';
}
else {
$this->nid_field = 'nid';
}
}
/**
* Provide link to node option
*/
function options_form(&$form) {
$form['link_to_node'] = array(
'#title' => t('Link this field to its node'),
'#type' => 'checkbox',
'#default_value' => $this->data->options['link_to_node'],
);
}
function render_link($data, $values) {
if (!empty($this->data->options['link_to_node'])) {
return l($data, "node/" . $values->{$this->node_field}, array('html' => TRUE));
}
else {
return $data;
}
}
function render($values) {
return $this->render_link(check_plain($values->{$this->field_alias}), $values);
}
}
/**
* Field handler to translate a node type into its readable form.
*/
class views_handler_field_node_type extends views_handler_field_node {
function render($values) {
$value = node_get_types('name', $values->{$this->field_alias});
return $this->render_link(check_plain($value), $values);
}
}
<?php
function user_views_data() {
$data['users']['table']['base'] = array(
'field' => 'uid',
'title' => t('User'),
);
$data['users']['table']['join']['node']['handler'] = 'views_join';
$data['users']['table']['join']['node']['arguments'] = array('users', 'node', 'uid', 'uid');
$data['users']['table']['group'] = t('User');
$data['users']['name']['field'] = array(
'group' => t('User'), // The group it appears in on the UI,
'title' => t('Name'), // The item it appears as on the UI,
'help' => t('The user/author name.'), // The help that appears on the UI,
'handler' => 'views_handler_field',
'arguments' => array(TRUE),
);
return $data;
}
\ No newline at end of file
<?php
// $Id$
/**
* This include file implements views functionality on behalf of book.module
*/
function book_views_tables() {
$tables['book'] = array(