plugins.inc 16.1 KB
Newer Older
1
<?php
2 3
// $Id$
/**
4 5
 * @file plugins.inc
 * Built in plugins for Views output handling.
6 7 8
 *
 */

9
/**
10 11 12 13 14 15
 * Implementation of hook_views_plugins
 */
function views_views_plugins() {
  return array(
    'module' => 'views', // This just tells our themes are elsewhere.
    'display' => array(
merlinofchaos's avatar
merlinofchaos committed
16 17 18 19 20 21 22
      'default' => array(
        'title' => t('Defaults'),
        'help' => t('Default settings for this view.'),
        'handler' => 'views_display_plugin_default',
        'no ui' => TRUE,
        'no remove' => TRUE,
      ),
23 24
      'page' => array(
        'title' => t('Page'),
merlinofchaos's avatar
merlinofchaos committed
25
        'help' => t('Display the view as a page, with a URL and menu links.'),
26
        'handler' => 'views_display_plugin_page',
27
        'uses_hook_menu' => TRUE,
28 29
      ),
      'block' => array(
30
        'title' => t('Block'),
merlinofchaos's avatar
merlinofchaos committed
31
        'help' => t('Display the view as a block.'),
32 33
        'handler' => 'views_display_plugin_block',
        'uses_hook_block' => TRUE,
34
      ),
merlinofchaos's avatar
merlinofchaos committed
35
/*
36 37 38 39 40
      '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',
      ),
merlinofchaos's avatar
merlinofchaos committed
41
*/
42 43 44 45 46 47
    ),
    'style' => array(
      'default' => array(
        'title' => t('Default'),
        'help' => t('Displays rows one after another.'),
        'handler' => 'views_style_plugin_default',
48
        'theme' => 'views_view_summary',
49 50 51 52 53 54 55 56 57 58 59 60 61
      ),
      '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',
      ),
62 63 64 65 66 67 68
      'default_summary' => array(
        'summary' => TRUE, // only shows up as a summary style
        'title' => t('Default'),
        'help' => t('Displays the default summary view'),
        'handler' => 'views_style_plugin_summary',
        'theme' => 'views_view_summary',
      ),
69 70 71 72 73 74 75 76
    ),
    'row' => array(
      'fields' => array(
        'title' => t('Fields'),
        'help' => t('Displays the fields with an optional template.'),
        'handler' => 'views_row_plugin',
        'theme' => 'views_view_row',
      ),
77 78
      'fields_summary' => array(
        'title' => t('Summary'),
79
        'help' => t('Displays the link to the argument and the row count.'),
80 81 82
        'handler' => 'views_row_plugin_summary',
        'theme' => 'views_view_row_summary',
      ),
83 84 85 86 87
    ),
  );

}

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
/**
 * Builds and return a list of all plugins available in the system.
 *
 * @return Nested array of plugins, grouped by type and
 */
function views_discover_plugins() {
  $cache = array('display' => array(), 'style' => array(), 'row' => array());
  // Get plugins from all mdoules.
  foreach (module_implements('views_plugins') as $module) {
    $function = $module . '_views_plugins';
    $result = $function();
    if (!is_array($result)) {
      continue;
    }

    $module_dir = isset($result['module']) ? $result['module'] : $module;
    // Setup automatic path/file finding for theme registration
    if ($module_dir == 'views') {
      $path = drupal_get_path('module', $module_dir) . '/theme';
      $file = 'theme.inc';
    }
    else {
      $path = drupal_get_path('module', $module_dir);
      $file = "$module.views.inc";
    }
    foreach ($result as $type => $info) {
      if ($type == 'module') {
        continue;
      }
      foreach ($info as $plugin => $def) {
        if (isset($def['theme']) && !isset($def['path'])) {
          $def['path'] = $path;
          $def['file'] = $file;
        }
        // merge the new data in
        $cache[$type][$plugin] = $def;
      }
    }
  }
  return $cache;
}

130 131 132 133 134 135 136 137 138 139 140
/**
 * @defgroup views_display_plugins Views' display plugins
 * @{
 * Display plugins control how Views interact with the rest of Drupal.
 *
 * They can handle creating Views from a Drupal page hook; they can
 * handle creating Views from a Drupal block hook. They can also
 * handle creating Views from an external module source, such as
 * a Panels pane, or an insert view, or a CCK field type.
 */

141 142 143 144 145 146 147 148 149 150 151
/**
 * The default display plugin handler. Display plugins handle options and
 * basic mechanisms for different output methods.
 */
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.
   */
152
  function init(&$view, &$display) {
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    $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'])) {
169
      return;
170 171 172 173
    }
    if (isset($this->default_display->display_options[$option])) {
      return $this->default_display->display_options[$option];
    }
174
  }
175

merlinofchaos's avatar
merlinofchaos committed
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
  /**
   * Because forms may be split up into sections, this provides
   * an easy URL to exactly the right section. Don't override this.
   */
  function option_link($text, $section) {
    return l($text, 'admin/build/views/nojs/display/' . $this->view->name . '/' . $this->display->id . '/' . $section, array('attributes' => array('class' => 'views-ajax-link')));
  }

  /**
   * Provide the default summary for options in the views UI.
   * The summary is part of a <dl> set, so be sure to put
   * everything in <dt>/<dd> blocks.
   */
  function options_summary() {
    $output = '';
    $output .= '<dt>' . t('Admin title: !title', array('!title' => $this->option_link($this->display->display_title, 'display_title'))) . '</dt>';
    return $output;
  }

195 196 197
  /**
   * Provide the default form for setting options.
   */
merlinofchaos's avatar
merlinofchaos committed
198 199 200 201 202 203 204 205 206 207 208 209
  function options_form(&$form, &$form_state) {
    switch ($form_state['section']) {
      case 'display_title':
        $form['display_title'] = array(
          '#type' => 'textfield',
          '#title' => t('Display title'),
          '#description' => t('This title will appear only in the administrative interface for the View.'),
          '#default_value' => $this->display->display_title,
        );
        break;
    }
  }
210

211 212 213 214 215 216 217 218 219
  /**
   * 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.
   */
merlinofchaos's avatar
merlinofchaos committed
220 221 222 223 224 225 226
  function options_submit($form, &$form_state) {
    switch ($form_state['section']) {
      case 'display_title':
        $this->display->display_title = $form_state['values']['display_title'];
        break;
    }
  }
227 228 229 230 231 232 233 234 235 236 237 238

  /**
   * Not all display plugins will support filtering
   */
  function render_filters() { }

  /**
   * Not all display plugins will have a 'more' link
   */
  function render_more_link() { }

  /**
239
   * Not all display plugins will have a feed icon.
240
   */
241 242 243 244
  function render_feed_icon() { }

  /**
   * Render the view's title for display
245
   * @todo Necessary? Hm.
246 247 248
   */
  function render_title() { }

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
  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'); }
268 269 270
  /**
   * If this display creates a block, implement one of these.
   */
271
  function hook_block($op = 'list', $delta = 0, $edit = array()) { return array(); }
272 273 274 275

  /**
   * If this display creates a page with a menu item, implement it here.
   */
276
  function hook_menu() { return array(); }
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292

  /**
   * Render this display.
   */
  function render() {
    $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);
  }

293 294 295
  /**
   * Determine if the user has access to this display of the view.
   *
296
   * @todo Implement this.
297 298
   */
  function access($account) { return TRUE; }
299
  /**
300 301 302 303
   * When used externally, this is how a view gets run and returns
   * data in the format required.
   */
  function execute() { }
304 305
}

merlinofchaos's avatar
merlinofchaos committed
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
/**
 * A plugin to handle defaults on a view.
 */
class views_display_plugin_default extends views_display_plugin {
  /**
   * The default execute handler fully renders the view.
   *
   * For the simplest use:
   * @code
   *   $output = $view->execute_display('default', $args);
   * @endcode
   *
   * For more complex usages, a view can be partially built:
   * @code
   *   $view->set_arguments($args);
   *   $view->build('default'); // Build the query
   *   $view->execute(); // Run the query
   *   $output = $view->render(); // Render the view
   * @endcode
   *
   * If short circuited at any point, look in $view->build_info for
   * information about the query. After execute, look in $view->result
   * for the object returned from db_query.
   *
   * You can also do:
   * @code
   *   $view->set_arguments($args);
   *   $output = $view->render('default'); // Render the view
   * @endcode
   *
   * This illustrates that render is smart enough to call build and execute
   * if these items have not already been accomplished.
   */
  function execute() {
    return $this->view->render();
  }
}

344 345 346 347 348 349
/**
 * The plugin that handles a full page.
 */
class views_display_plugin_page extends views_display_plugin {
  var $uses_hook_menu = TRUE;

350 351 352 353 354
  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);
355

356 357 358 359
    // 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
360
      'page callback' => 'views_page',
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
      '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();
  }
387 388 389 390 391 392 393
}

/**
 * The plugin that handles a block.
 */
class views_display_plugin_block extends views_display_plugin {
  var $uses_hook_block = TRUE;
394

395
  /**
396 397 398 399 400 401 402 403 404 405 406 407 408
   * 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.
409
   */
410 411 412 413 414 415 416
  function execute() {
    // 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;
  }
417 418
}

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
/**
 * @}
 */

/**
 * @defgroup views_style_plugins Views' style plugins
 * @{
 * Style plugins control how a view is rendered. For example, they
 * can choose to display a collection of fields, node_view() output,
 * table output, or any kind of crazy output they want.
 *
 * Many style plugins can have an optional 'row' plugin, that displays
 * a single record. Not all style plugins can utilize this, so it is
 * up to the plugin to set this up and call through to the row plugin.
 */

435 436 437 438 439 440 441
/**
 * Base class to define a style plugin handler.
 */
class views_style_plugin extends views_object {
  var $needs_fields = FALSE;
  var $needs_headers = FALSE;

442
  function init(&$view, &$display) {
443 444 445 446 447 448 449 450 451
    $this->view = $view;
    $this->display = $display;
    $this->options = $display->style_options;
  }

  /**
   * Provide a form for setting options.
   */
  function options_form(&$form) { }
452

453 454 455 456 457 458 459 460 461 462 463 464 465 466
  /**
   * 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) { }
}

467 468 469 470
/**
 * Default style plugin to render rows one after another with no
 * decorations.
 */
471 472 473
class views_style_plugin_default extends views_style_plugin {
  // TEMP HACK
  var $row_plugin = 'views_row_plugin';
474
//  var $row_plugin = 'views_row_plugin_node_view';
475 476 477 478
  function options_form(&$form) {
    // provide an option form to select from our list of node renderers
  }

479 480 481
  /**
   * Render the given style.
   */
482
  function render() {
483
    // @todo: This needs to be able to support either a database resource OR
484 485
    // an array, because our input format doesn't actually have to be from
    // a query.
486
    $plugin = new $this->row_plugin;
487 488
    $rows = '';
    while ($row = db_fetch_object($this->view->result)) {
489
      // @todo: Include separator as an option.
490 491 492 493 494 495
      $rows .= $plugin->render($this->view, $row);
    }
    return theme(array('views_view_rows__' . $this->view->name, 'views_view_rows'), $this->view, $rows);
  }
}

496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
/**
 * The default style plugin for summaries.
 */
class views_style_plugin_summary extends views_style_plugin {
  // TEMP HACK
  var $row_plugin = 'views_row_plugin_summary';
  function options_form(&$form) {
    // 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 $this->row_plugin;
    $rows = array();
    while ($row = db_fetch_object($this->view->result)) {
      // @todo: Include separator as an option.
      $rows[] = $plugin->render($this->view, $row);
    }
    return theme(array('views_view_summary__' . $this->view->name, 'views_view_summary'), $this->view, $rows);
  }
}

/**
 * @}
 */

/**
 * @defgroup views_row_plugins Views' row plugins
 * @{
 *
 * Row plugins control how Views outputs an individual record. They are
 * tightly coupled to style plugins, in that a style plugin is what calls
 * the row plugin.
 */

536 537 538 539 540 541 542 543 544
/**
 * 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);
  }
}
545 546 547 548 549 550 551 552 553 554 555 556 557 558

/**
 * Default plugin to view a single row of a table. This is really just a wrapper around
 * a theme function.
 */
class views_row_plugin_summary extends views_object {
  function render(&$view, $row) {
    return theme(array('views_view_row_summary__' . $view->name, 'views_view_row_summary'), $view, $row);
  }
}

/**
 * @}
 */