Commit 6b8d66b5 authored by webchick's avatar webchick
Browse files

Issue #1821654 by damiankloip, dawehner: Refactor Page based display plugin classes.

parent 881edb14
......@@ -90,7 +90,6 @@ public function execute() {
* This output is returned as an array.
*/
public function optionsSummary(&$categories, &$options) {
// It is very important to call the parent function here:
parent::optionsSummary($categories, $options);
$categories['block'] = array(
......@@ -151,7 +150,6 @@ protected function getCacheType() {
* Provide the default form for setting options.
*/
public function buildOptionsForm(&$form, &$form_state) {
// It is very important to call the parent function here:
parent::buildOptionsForm($form, $form_state);
switch ($form_state['section']) {
......@@ -189,7 +187,6 @@ public function buildOptionsForm(&$form, &$form_state) {
* There is no need for this function to actually store the data.
*/
public function submitOptionsForm(&$form, &$form_state) {
// It is very important to call the parent function here:
parent::submitOptionsForm($form, $form_state);
switch ($form_state['section']) {
case 'display_id':
......
......@@ -2,13 +2,13 @@
/**
* @file
* Definition of Drupal\views\Plugin\views\display\DisplayPluginBase.
* Contains Drupal\views\Plugin\views\display\DisplayPluginBase.
*/
namespace Drupal\views\Plugin\views\display;
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\PluginBase;
use \Drupal\views\Plugin\views\PluginBase;
/**
* @defgroup views_display_plugins Views display plugins
......@@ -333,9 +333,12 @@ public function useMoreText() {
* @return bool
*/
public function acceptAttachments() {
if (!$this->usesAttachments()) {
// To be able to accept attachments this display have to be able to use
// attachments but at the same time, you cannot attach a display to itself.
if (!$this->usesAttachments() || ($this->definition['id'] == $this->view->current_display)) {
return FALSE;
}
if (!empty($this->view->argument) && $this->getOption('hide_attachment_summary')) {
foreach ($this->view->argument as $argument_id => $argument) {
if ($argument->needsStylePlugin() && empty($argument->argument_validated)) {
......@@ -343,6 +346,7 @@ public function acceptAttachments() {
}
}
}
return TRUE;
}
......@@ -745,7 +749,7 @@ public function usesFields() {
* @param string $type
* The type of the plugin.
*
* @return Drupal\views\Plugin\views\PluginBase
* @return \Drupal\views\Plugin\views\PluginBase
*/
public function getPlugin($type) {
// Look up the plugin name to use for this instance.
......
......@@ -2,7 +2,7 @@
/**
* @file
* Definition of Drupal\views\Plugin\views\display\Feed.
* Contains Drupal\views\Plugin\views\display\Feed.
*/
namespace Drupal\views\Plugin\views\display;
......@@ -16,8 +16,6 @@
/**
* The plugin that handles a feed, such as RSS or atom.
*
* For the most part, feeds are page displays but with some subtle differences.
*
* @ingroup views_display_plugins
*
* @Plugin(
......@@ -28,7 +26,7 @@
* admin = @Translation("Feed")
* )
*/
class Feed extends Page {
class Feed extends PathPluginBase {
/**
* Whether the display allows the use of AJAX or not.
......@@ -57,47 +55,60 @@ public function init(ViewExecutable $view, &$display, $options = NULL) {
}
}
public function usesBreadcrumb() { return FALSE; }
protected function getStyleType() { return 'feed'; }
/**
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::getStyleType().
*/
protected function getStyleType() {
return 'feed';
}
/**
* Feeds do not go through the normal page theming mechanism. Instead, they
* go through their own little theme function and then return NULL so that
* Drupal believes that the page has already rendered itself...which it has.
* Overrides \Drupal\views\Plugin\views\display\PathPluginBase::execute().
*/
public function execute() {
parent::execute();
$output = $this->view->render();
if (empty($output)) {
throw new NotFoundHttpException();
}
$response = $this->view->getResponse();
$response->setContent($output);
return $response;
}
/**
* Overrides \Drupal\views\Plugin\views\display\PathPluginBase::preview().
*/
public function preview() {
if (!empty($this->view->live_preview)) {
return '<pre>' . check_plain($this->view->render()) . '</pre>';
}
return $this->view->render();
}
/**
* Instead of going through the standard views_view.tpl.php, delegate this
* to the style handler.
* Overrides \Drupal\views\Plugin\views\display\PathPluginBase::render().
*/
public function render() {
return $this->view->style_plugin->render($this->view->result);
}
/**
* Overrides \Drupal\views\Plugin\views\displays\DisplayPluginBase::defaultableSections().
*/
public function defaultableSections($section = NULL) {
$sections = parent::defaultableSections($section);
if (in_array($section, array('style', 'row'))) {
return FALSE;
}
$sections = parent::defaultableSections($section);
// Tell views our sitename_title option belongs in the title section.
if ($section == 'title') {
$sections[] = 'sitename_title';
......@@ -108,6 +119,9 @@ public function defaultableSections($section = NULL) {
return $sections;
}
/**
* Overrides \Drupal\views\Plugin\views\display\PathPluginBase::defineOptions().
*/
protected function defineOptions() {
$options = parent::defineOptions();
......@@ -124,11 +138,13 @@ protected function defineOptions() {
return $options;
}
/**
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::optionsSummary().
*/
public function optionsSummary(&$categories, &$options) {
// It is very important to call the parent function here:
parent::optionsSummary($categories, $options);
// Since we're childing off the 'page' type, we'll still *call* our
// Since we're childing off the 'path' type, we'll still *call* our
// category 'page' but let's override it so it says feed settings.
$categories['page'] = array(
'title' => t('Feed settings'),
......@@ -142,9 +158,6 @@ public function optionsSummary(&$categories, &$options) {
$options['title']['value'] = t('Using the site name');
}
// I don't think we want to give feeds menus directly.
unset($options['menu']);
$displays = array_filter($this->getOption('displays'));
if (count($displays) > 1) {
$attach_to = t('Multiple displays');
......@@ -169,7 +182,7 @@ public function optionsSummary(&$categories, &$options) {
}
/**
* Provide the default form for setting options.
* Overrides \Drupal\views\Plugin\views\display\PathPluginBase::buildOptionsForm().
*/
public function buildOptionsForm(&$form, &$form_state) {
// It is very important to call the parent function here.
......@@ -214,11 +227,9 @@ public function buildOptionsForm(&$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.
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::submitOptionsForm().
*/
public function submitOptionsForm(&$form, &$form_state) {
// It is very important to call the parent function here:
parent::submitOptionsForm($form, $form_state);
switch ($form_state['section']) {
case 'title':
......@@ -231,7 +242,7 @@ public function submitOptionsForm(&$form, &$form_state) {
}
/**
* Attach to another view.
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::attachTo().
*/
public function attachTo($display_id) {
$displays = $this->getOption('displays');
......@@ -254,6 +265,9 @@ public function attachTo($display_id) {
}
}
/**
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::usesLinkDisplay().
*/
public function usesLinkDisplay() {
return TRUE;
}
......
......@@ -2,7 +2,7 @@
/**
* @file
* Definition of Drupal\views\Plugin\views\display\Page.
* Contains Drupal\views\Plugin\views\display\Page.
*/
namespace Drupal\views\Plugin\views\display;
......@@ -27,7 +27,7 @@
* admin = @Translation("Page")
* )
*/
class Page extends DisplayPluginBase {
class Page extends PathPluginBase {
/**
* Whether the display allows attachments.
......@@ -37,15 +37,18 @@ class Page extends DisplayPluginBase {
protected $usesAttachments = TRUE;
/**
* The page display has a path.
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::usesBreadcrumb().
*/
public function hasPath() { return TRUE; }
public function usesBreadcrumb() { return TRUE; }
public function usesBreadcrumb() {
return TRUE;
}
/**
* Overrides \Drupal\views\Plugin\views\display\PathPluginBase::defineOptions().
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['path'] = array('default' => '');
$options['menu'] = array(
'contains' => array(
'type' => array('default' => 'none'),
......@@ -72,221 +75,32 @@ protected function defineOptions() {
}
/**
* Add this display's path information to Drupal's menu system.
*/
public function executeHookMenu($callbacks) {
$items = array();
// Replace % with the link to our standard views argument loader
// views_arg_load -- which lives in views.module
$bits = explode('/', $this->getOption('path'));
$page_arguments = array($this->view->storage->get('name'), $this->display['id']);
$this->view->initHandlers();
$view_arguments = $this->view->argument;
// Replace % with %views_arg for menu autoloading and add to the
// page arguments so the argument actually comes through.
foreach ($bits as $pos => $bit) {
if ($bit == '%') {
$argument = array_shift($view_arguments);
if (!empty($argument->options['specify_validation']) && $argument->options['validate']['type'] != 'none') {
$bits[$pos] = '%views_arg';
}
$page_arguments[] = $pos;
}
}
$path = implode('/', $bits);
$access_plugin = $this->getPlugin('access');
if (!isset($access_plugin)) {
$access_plugin = views_get_plugin('access', 'none');
}
// Get access callback might return an array of the callback + the dynamic arguments.
$access_plugin_callback = $access_plugin->get_access_callback();
if (is_array($access_plugin_callback)) {
$access_arguments = array();
// Find the plugin arguments.
$access_plugin_method = array_shift($access_plugin_callback);
$access_plugin_arguments = array_shift($access_plugin_callback);
if (!is_array($access_plugin_arguments)) {
$access_plugin_arguments = array();
}
$access_arguments[0] = array($access_plugin_method, &$access_plugin_arguments);
// Move the plugin arguments to the access arguments array.
$i = 1;
foreach ($access_plugin_arguments as $key => $value) {
if (is_int($value)) {
$access_arguments[$i] = $value;
$access_plugin_arguments[$key] = $i;
$i++;
}
}
}
else {
$access_arguments = array($access_plugin_callback);
}
if ($path) {
$items[$path] = array(
// default views page entry
'page callback' => 'views_page',
'page arguments' => $page_arguments,
// Default access check (per display)
'access callback' => 'views_access',
'access arguments' => $access_arguments,
// Identify URL embedded arguments and correlate them to a handler
'load arguments' => array($this->view->storage->get('name'), $this->display['id'], '%index'),
);
$menu = $this->getOption('menu');
if (empty($menu)) {
$menu = array('type' => 'none');
}
// Set the title and description if we have one.
if ($menu['type'] != 'none') {
$items[$path]['title'] = $menu['title'];
$items[$path]['description'] = $menu['description'];
}
if (isset($menu['weight'])) {
$items[$path]['weight'] = intval($menu['weight']);
}
switch ($menu['type']) {
case 'none':
default:
$items[$path]['type'] = MENU_CALLBACK;
break;
case 'normal':
$items[$path]['type'] = MENU_NORMAL_ITEM;
// Insert item into the proper menu
$items[$path]['menu_name'] = $menu['name'];
break;
case 'tab':
$items[$path]['type'] = MENU_LOCAL_TASK;
break;
case 'default tab':
$items[$path]['type'] = MENU_DEFAULT_LOCAL_TASK;
break;
}
// Add context for contextual links.
// @see menu_contextual_links()
if (!empty($menu['context'])) {
$items[$path]['context'] = MENU_CONTEXT_INLINE;
}
// If this is a 'default' tab, check to see if we have to create teh
// parent menu item.
if ($menu['type'] == 'default tab') {
$tab_options = $this->getOption('tab_options');
if (!empty($tab_options['type']) && $tab_options['type'] != 'none') {
$bits = explode('/', $path);
// Remove the last piece.
$bit = array_pop($bits);
// we can't do this if they tried to make the last path bit variable.
// @todo: We can validate this.
if ($bit != '%views_arg' && !empty($bits)) {
$default_path = implode('/', $bits);
$items[$default_path] = array(
// default views page entry
'page callback' => 'views_page',
'page arguments' => $page_arguments,
// Default access check (per display)
'access callback' => 'views_access',
'access arguments' => $access_arguments,
// Identify URL embedded arguments and correlate them to a handler
'load arguments' => array($this->view->storage->get('name'), $this->display['id'], '%index'),
'title' => $tab_options['title'],
'description' => $tab_options['description'],
'menu_name' => $tab_options['name'],
);
switch ($tab_options['type']) {
default:
case 'normal':
$items[$default_path]['type'] = MENU_NORMAL_ITEM;
break;
case 'tab':
$items[$default_path]['type'] = MENU_LOCAL_TASK;
break;
}
if (isset($tab_options['weight'])) {
$items[$default_path]['weight'] = intval($tab_options['weight']);
}
}
}
}
}
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.
* Overrides \Drupal\views\Plugin\views\display\PathPluginBase::execute().
*/
public function execute() {
parent::execute();
// Let the world know that this is the page view we're using.
views_set_page_view($this->view);
// 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();
if (!empty($this->view->build_info['fail'])) {
throw new NotFoundHttpException();
}
if (!empty($this->view->build_info['denied'])) {
throw new AccessDeniedHttpException();
}
$this->view->getBreadcrumb(TRUE);
// And now render the view.
$render = $this->view->render();
// First execute the view so it's possible to get tokens for the title.
// And the title, which is much easier.
drupal_set_title(filter_xss_admin($this->view->getTitle()), PASS_THROUGH);
return $render;
}
/**
* Provide the summary for page options in the views UI.
*
* This output is returned as an array.
* Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::optionsSummary().
*/
public function optionsSummary(&$categories, &$options) {
// It is very important to call the parent function here:
parent::optionsSummary($categories, $options);
$categories['page'] = array(
'title' => t('Page settings'),
'column' => 'second',
'build' => array(
'#weight' => -10,
),
);
$path = strip_tags('/' . $this->getOption('path'));
if (empty($path)) {
$path = t('None');
}
$options['path'] = array(
'category' => 'page',
'title' => t('Path'),
'value' => views_ui_truncate($path, 24),
);
$menu = $this->getOption('menu');
if (!is_array($menu)) {
$menu = array('type' => 'none');
......@@ -319,24 +133,12 @@ public function optionsSummary(&$categories, &$options) {
}
/**
* Provide the default form for setting options.
* Overrides \Drupal\views\Plugin\views\display\callbackPluginBase::buildOptionsForm().
*/
public function buildOptionsForm(&$form, &$form_state) {
// It is very important to call the parent function here:
parent::buildOptionsForm($form, $form_state);
switch ($form_state['section']) {
case 'path':
$form['#title'] .= t('The menu path or URL of this view');
$form['path'] = array(
'#type' => 'textfield',
'#description' => t('This view will be displayed by visiting this path on your site. You may use "%" in your URL to represent values that will be used for contextual filters: For example, "node/%/feed".'),
'#default_value' => $this->getOption('path'),
'#field_prefix' => '<span dir="ltr">' . url(NULL, array('absolute' => TRUE)),
'#field_suffix' => '</span>&lrm;',
'#attributes' => array('dir' => 'ltr'),
);
break;
case 'menu':
$form['#title'] .= t('Menu item entry');
$form['menu'] = array(
......@@ -561,50 +363,39 @@ public function buildOptionsForm(&$form, &$form_state) {
}
}
/**
* Overrides \Drupal\views\Plugin\views\display\callbackPluginBase::validateOptionsForm().
*/
public function validateOptionsForm(&$form, &$form_state) {
// It is very important to call the parent function here:
parent::validateOptionsForm($form, $form_state);
switch ($form_state['section']) {
case 'path':
if (strpos($form_state['values']['path'], '$arg') !== FALSE) {
form_error($form['path'], t('"$arg" is no longer supported. Use % instead.'));
}
if (strpos($form_state['values']['path'], '%') === 0) {
form_error($form['path'], t('"%" may not be used for the first segment of a path.'));
}
// automatically remove '/' and trailing whitespace from path.
$form_state['values']['path'] = trim($form_state['values']['path'], '/ ');
break;
case 'menu':
$path = $this->getOption('path');
if ($form_state['values']['menu']['type'] == 'normal' && strpos($path, '%') !== FALSE) {
form_error($form['menu']['type'], t('Views cannot create normal menu items for paths with a % in them.'));
}
if ($form_state['section'] == 'menu') {
$path = $this->getOption('path');
if ($form_state['values']['menu']['type'] == 'normal' && strpos($path, '%') !== FALSE) {
form_error($form['menu']['type'], t('Views cannot create normal menu items for paths with a % in them.'));
}
if ($form_state['values']['menu']['type'] == 'default tab' || $form_state['values']['menu']['type'] == 'tab') {
$bits = explode('/', $path);
$last = array_pop($bits);
if ($last == '%') {
form_error($form['menu']['type'], t('A display whose path ends with a % cannot be a tab.'));
}
if ($form_state['values']['menu']['type'] == 'default tab' || $form_state['values']['menu']['type'] == 'tab') {
$bits = explode('/', $path);
$last = array_pop($bits);
if ($last == '%') {
form_error($form['menu']['type'], t('A display whose path ends with a % cannot be a tab.'));
}
}
if ($form_state['values']['menu']['type'] != 'none' && empty($form_state['values']['menu']['title'])) {
form_error($form['menu']['title'], t('Title is required for this menu type.'));
}
break;
if ($form_state['values']['menu']['type'] != 'none' && empty($form_state['values']['menu']['title'])) {
form_error($form['menu']['title'], t('Title is required for this menu type.'));
}
}
}
/**
* Overrides \Drupal\views\Plugin\views\display\callbackPluginBase::submitOptionsForm().
*/
public function submitOptionsForm(&$form, &$form_state) {
// It is very important to call the parent function here:
parent::submitOptionsForm($form, $form_state);
switch ($form_state['section']) {
case 'path':
$this->setOption('path', $form_state['values']['path']);
break;