Commit 4addda03 authored by tim.plunkett's avatar tim.plunkett

Issue #1760284 by tim.plunkett: Update the Views copy of the core Entity List API.

parent ec3acb2a
...@@ -7,68 +7,20 @@ ...@@ -7,68 +7,20 @@
namespace Drupal\views; namespace Drupal\views;
use Drupal\views_ui_listing\EntityListControllerBase; use Drupal\views_ui_listing\EntityListController;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
/** /**
* Provides a listing of Views. * Provides a listing of Views.
*/ */
class ViewListController extends EntityListControllerBase { class ViewListController extends EntityListController {
public function __construct($entity_type, $entity_info = FALSE) {
parent::__construct($entity_type, $entity_info);
}
/** /**
* Overrides Drupal\views_ui_listing\EntityListControllerBase::hookMenu(); * Overrides Drupal\views_ui_listing\EntityListController::load();
*/ */
public function hookMenu() { public function load() {
// Find the path and the number of path arguments. $entities = parent::load();
$path = $this->entityInfo['list path']; uasort($entities, function ($a, $b) {
$path_count = count(explode('/', $path));
$items = parent::hookMenu();
// Override the access callback.
// @todo Probably won't need to specify user access.
$items[$path]['title'] = 'Views';
$items[$path]['description'] = 'Manage customized lists of content.';
$items[$path]['access callback'] = 'user_access';
$items[$path]['access arguments'] = array('administer views');
// Add a default local task, so we have tabs.
$items["$path/list"] = array(
'title' => 'List',
'weight' => -10,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
// Set up the base for AJAX callbacks.
$ajax_base = array(
'page callback' => 'views_ui_listing_ajax_callback',
'page arguments' => array($this, $path_count + 1, $path_count + 2),
'access callback' => 'user_access',
'access arguments' => array('administer views'),
'type' => MENU_CALLBACK,
);
// Add an enable link.
$items["$path/view/%views_ui/enable"] = array(
'title' => 'Enable a view',
) + $ajax_base;
// Add a disable link.
$items["$path/view/%views_ui/disable"] = array(
'title' => 'Disable a view',
) + $ajax_base;
return $items;
}
/**
* Overrides Drupal\views_ui_listing\EntityListControllerBase::getList();
*/
public function getList() {
$list = parent::getList();
uasort($list, function ($a, $b) {
$a_enabled = $a->isEnabled(); $a_enabled = $a->isEnabled();
$b_enabled = $b->isEnabled(); $b_enabled = $b->isEnabled();
if ($a_enabled != $b_enabled) { if ($a_enabled != $b_enabled) {
...@@ -76,14 +28,14 @@ public function getList() { ...@@ -76,14 +28,14 @@ public function getList() {
} }
return $a->id() > $b->id(); return $a->id() > $b->id();
}); });
return $list; return $entities;
} }
/** /**
* Overrides Drupal\views_ui_listing\EntityListControllerBase::getRowData(); * Overrides Drupal\views_ui_listing\EntityListController::buildRow();
*/ */
public function getRowData(EntityInterface $view) { public function buildRow(EntityInterface $view) {
$operations = $this->buildActionLinks($view); $operations = $this->buildOperations($view);
$operations['#theme'] = 'links__ctools_dropbutton'; $operations['#theme'] = 'links__ctools_dropbutton';
return array( return array(
'data' => array( 'data' => array(
...@@ -99,9 +51,9 @@ public function getRowData(EntityInterface $view) { ...@@ -99,9 +51,9 @@ public function getRowData(EntityInterface $view) {
} }
/** /**
* Overrides Drupal\views_ui_listing\EntityListControllerBase::getRowData(); * Overrides Drupal\views_ui_listing\EntityListController::buildHeader();
*/ */
public function getHeaderData() { public function buildHeader() {
return array( return array(
'view_name' => array( 'view_name' => array(
'data' => t('View name'), 'data' => t('View name'),
...@@ -119,7 +71,7 @@ public function getHeaderData() { ...@@ -119,7 +71,7 @@ public function getHeaderData() {
'data' => t('Path'), 'data' => t('Path'),
'class' => array('views-ui-path'), 'class' => array('views-ui-path'),
), ),
'actions' => array( 'operations' => array(
'data' => t('Operations'), 'data' => t('Operations'),
'class' => array('views-ui-operations'), 'class' => array('views-ui-operations'),
), ),
...@@ -127,30 +79,33 @@ public function getHeaderData() { ...@@ -127,30 +79,33 @@ public function getHeaderData() {
} }
/** /**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::defineActionLinks(); * Implements Drupal\views_ui_listing\EntityListController::getOperations();
*/ */
public function defineActionLinks(EntityInterface $view) { public function getOperations(EntityInterface $view) {
$path = $this->entityInfo['list path'] . '/view/' . $view->id(); $uri = $view->uri();
$enabled = $view->isEnabled(); $path = $uri['path'] . '/view/' . $view->id();
if (!$enabled) { $definition['edit'] = array(
'title' => t('Edit'),
'href' => "$path/edit",
'weight' => -5,
);
if (!$view->isEnabled()) {
$definition['enable'] = array( $definition['enable'] = array(
'title' => t('Enable'), 'title' => t('Enable'),
'ajax' => TRUE, 'ajax' => TRUE,
'token' => TRUE, 'token' => TRUE,
'href' => "$path/enable", 'href' => "$path/enable",
'weight' => -10,
); );
} }
$definition['edit'] = array( else {
'title' => t('Edit'),
'href' => "$path/edit",
);
if ($enabled) {
$definition['disable'] = array( $definition['disable'] = array(
'title' => t('Disable'), 'title' => t('Disable'),
'ajax' => TRUE, 'ajax' => TRUE,
'token' => TRUE, 'token' => TRUE,
'href' => "$path/disable", 'href' => "$path/disable",
'weight' => 0,
); );
} }
// This property doesn't exist yet. // This property doesn't exist yet.
...@@ -158,22 +113,24 @@ public function defineActionLinks(EntityInterface $view) { ...@@ -158,22 +113,24 @@ public function defineActionLinks(EntityInterface $view) {
$definition['revert'] = array( $definition['revert'] = array(
'title' => t('Revert'), 'title' => t('Revert'),
'href' => "$path/revert", 'href' => "$path/revert",
'weight' => 5,
); );
} }
else { else {
$definition['delete'] = array( $definition['delete'] = array(
'title' => t('Delete'), 'title' => t('Delete'),
'href' => "$path/delete", 'href' => "$path/delete",
'weight' => 10,
); );
} }
return $definition; return $definition;
} }
/** /**
* Overrides Drupal\views_ui_listing\EntityListControllerBase::renderList(); * Overrides Drupal\views_ui_listing\EntityListController::render();
*/ */
public function renderList() { public function render() {
$list = parent::renderList(); $list = parent::render();
$list['#attached']['css'] = views_ui_get_admin_css(); $list['#attached']['css'] = views_ui_get_admin_css();
return $list; return $list;
} }
......
...@@ -161,6 +161,16 @@ public function getModule() { ...@@ -161,6 +161,16 @@ public function getModule() {
return $this->module; return $this->module;
} }
/**
* Overrides Drupal\Core\Entity\EntityInterface::uri().
*/
public function uri() {
$info = $this->entityInfo();
return array(
'path' => $info['list path'],
);
}
/** /**
* Overrides Drupal\Core\Entity\EntityInterface::id(). * Overrides Drupal\Core\Entity\EntityInterface::id().
*/ */
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
use Drupal\views\ViewExecutable; use Drupal\views\ViewExecutable;
use Drupal\views\ViewUI; use Drupal\views\ViewUI;
use Drupal\Core\Entity\EntityInterface;
/** /**
* Implements hook_menu(). * Implements hook_menu().
...@@ -20,6 +21,12 @@ function views_ui_menu() { ...@@ -20,6 +21,12 @@ function views_ui_menu() {
'access arguments' => array('administer views'), 'access arguments' => array('administer views'),
'file' => 'includes/admin.inc', 'file' => 'includes/admin.inc',
); );
// Set up the base for AJAX callbacks.
$ajax_base = array(
'page callback' => 'views_ui_ajax_callback',
'page arguments' => array(4, 5),
'type' => MENU_CALLBACK,
) + $base;
// Top-level Views module pages (not tied to a particular View). // Top-level Views module pages (not tied to a particular View).
$items['admin/structure/views/add'] = array( $items['admin/structure/views/add'] = array(
...@@ -28,6 +35,26 @@ function views_ui_menu() { ...@@ -28,6 +35,26 @@ function views_ui_menu() {
'type' => MENU_LOCAL_ACTION, 'type' => MENU_LOCAL_ACTION,
) + $base; ) + $base;
$items['admin/structure/views'] = array(
'title' => 'Views',
'description' => 'Manage customized lists of content.',
'page callback' => 'views_ui_list_page',
) + $base;
$items['admin/structure/views/list'] = array(
'title' => 'List',
'weight' => -10,
'type' => MENU_DEFAULT_LOCAL_TASK,
) + $base;
$items['admin/structure/views/view/%views_ui/enable'] = array(
'title' => 'Enable a view',
) + $ajax_base;
$items['admin/structure/views/view/%views_ui/disable'] = array(
'title' => 'Disable a view',
) + $ajax_base;
/* /*
// Top-level Views module pages (not tied to a particular View). // Top-level Views module pages (not tied to a particular View).
$items['admin/structure/views/add-template'] = array( $items['admin/structure/views/add-template'] = array(
...@@ -752,3 +779,43 @@ function views_ui_truncate($string, $length) { ...@@ -752,3 +779,43 @@ function views_ui_truncate($string, $length) {
function views_ui_load($name) { function views_ui_load($name) {
return views_get_view($name); return views_get_view($name);
} }
/**
* Page callback: Calls a method on a view and reloads the listing page.
*
* @param Drupal\views\ViewExectuable $view
* The config entity being acted upon.
* @param string $op
* The operation to perform, e.g., 'enable' or 'disable'.
*
* @return mixed
* Either returns the listing page as JSON, or calls drupal_goto() to
* redirect back to the listing page.
*/
function views_ui_ajax_callback(ViewExecutable $view, $op) {
$controller = views_ui_entity_list_controller('view');
// Perform the operation.
$view->storage->$op();
// If the request is via AJAX, return the rendered list as JSON.
if (drupal_container()->get('request')->request->get('js')) {
return $controller->renderListAJAX();
}
// Otherwise, redirect back to the page.
else {
drupal_goto($controller->getPath());
}
}
/**
* Page callback: Lists all of the views.
*
* @return array
* A render array for a page containing a list of views.
*
* @see views_ui_menu()
*/
function views_ui_list_page() {
$controller = views_ui_entity_list_controller('view');
return $controller->render();
}
<?php <?php
/** /**
* Definition of Drupal\views_ui_listing\EntityListControllerBase. * @file
* Definition of Drupal\views_ui_listing\EntityListController.
*/ */
namespace Drupal\views_ui_listing; namespace Drupal\views_ui_listing;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
/** /**
* Abstract base class for config entity listing plugins. * Provides a generic implementation of an entity list controller.
*/ */
abstract class EntityListControllerBase implements EntityListControllerInterface { class EntityListController implements EntityListControllerInterface {
/** /**
* The Config storage controller class. * The entity storage controller class.
* *
* @var Drupal\config\ConfigStorageController * @var Drupal\Core\Entity\EntityStorageControllerInterface
*/ */
protected $storage; protected $storage;
/** /**
* The Config entity type. * The entity type name.
* *
* @var string * @var string
*/ */
protected $entityType; protected $entityType;
/** /**
* The Config entity info. * The entity info array.
* *
* @var array * @var array
*
* @see entity_get_info()
*/ */
protected $entityInfo; protected $entityInfo;
/** /**
* If ajax links are used on the listing page. * Constructs a new EntityListController object.
* *
* @var bool * @param string $entity_type.
* The type of entity to be listed.
*/ */
protected $usesAJAX; public function __construct($entity_type) {
public function __construct($entity_type, $entity_info = FALSE) {
$this->entityType = $entity_type; $this->entityType = $entity_type;
$this->storage = entity_get_controller($entity_type); $this->storage = entity_get_controller($this->entityType);
if (!$entity_info) { $this->entityInfo = entity_get_info($this->entityType);
$entity_info = entity_get_info($entity_type);
}
$this->entityInfo = $entity_info;
} }
/** /**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::getList(); * Implements Drupal\views_ui_listing\EntityListControllerInterface::getStorageController().
*/
public function getList() {
return $this->storage->load();
}
/**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::getStorageController();
*/ */
public function getStorageController() { public function getStorageController() {
return $this->storage; return $this->storage;
} }
public function getPath() { /**
return $this->entityInfo['list path']; * Implements Drupal\views_ui_listing\EntityListControllerInterface::load().
*/
public function load() {
return $this->storage->load();
} }
/** /**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::hookMenu(); * Implements Drupal\views_ui_listing\EntityListControllerInterface::getOperations().
*/ */
public function hookMenu() { public function getOperations(EntityInterface $entity) {
$items = array(); $uri = $entity->uri();
$items[$this->entityInfo['list path']] = array( $operations['edit'] = array(
'page callback' => 'views_ui_listing_entity_listing_page', 'title' => t('Edit'),
'page arguments' => array($this->entityType), 'href' => $uri['path'] . '/edit',
// @todo Add a proper access callback here. 'options' => $uri['options'],
'access callback' => TRUE, 'weight' => 10,
);
$operations['delete'] = array(
'title' => t('Delete'),
'href' => $uri['path'] . '/delete',
'options' => $uri['options'],
'weight' => 100,
); );
return $items; return $operations;
} }
/** /**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::getRowData(); * Retrieves the entity list path from the entity information.
*
* @return string
* The internal system path where the entity list will be rendered.
*
* @todo What is this method for, other than fetching the list path? Is this
* for http://drupal.org/node/1783964 ? Should it be on the interface?
*/ */
public function getRowData(EntityInterface $entity) { public function getPath() {
$row = array(); return $this->entityInfo['list path'];
$row['id'] = $entity->id();
$row['label'] = $entity->label();
$actions = $this->buildActionLinks($entity);
$row['actions'] = drupal_render($actions);
return $row;
} }
/** /**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::getHeaderData(); * Implements Drupal\views_ui_listing\EntityListControllerInterface::buildHeader().
*/ */
public function getHeaderData() { public function buildHeader() {
$row = array();
$row['id'] = t('ID');
$row['label'] = t('Label'); $row['label'] = t('Label');
$row['actions'] = t('Actions'); $row['id'] = t('Machine name');
$row['operations'] = t('Operations');
return $row; return $row;
} }
/** /**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::buildActionLinks(); * Implements Drupal\views_ui_listing\EntityListControllerInterface::buildRow().
*/ */
public function buildActionLinks(EntityInterface $entity) { public function buildRow(EntityInterface $entity) {
$links = array(); $row['label'] = $entity->label();
$row['id'] = $entity->id();
foreach ($this->defineActionLinks($entity) as $definition) { $operations = $this->buildOperations($entity);
$attributes = array(); $row['operations'] = drupal_render($operations);
return $row;
if (!empty($definition['ajax'])) {
$attributes['class'][] = 'use-ajax';
// Set this to true if we haven't already.
if (!isset($this->usesAJAX)) {
$this->usesAJAX = TRUE;
}
}
$links[] = array(
'title' => $definition['title'],
'href' => $definition['href'],
'attributes' => $attributes,
);
}
return array(
'#theme' => 'links',
'#links' => $links,
);
} }
/** /**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::renderList(); * Implements Drupal\views_ui_listing\EntityListControllerInterface::buildOperations().
*/ */
public function renderList() { public function buildOperations(EntityInterface $entity) {
$rows = array(); // Retrieve and sort operations.
$operations = $this->getOperations($entity);
foreach ($this->getList() as $entity) { uasort($operations, 'drupal_sort_weight');
$rows[] = $this->getRowData($entity); $build = array(
} '#theme' => 'links',
'#links' => $operations,
// Add core AJAX library if we need to.
if (!empty($this->usesAJAX)) {
drupal_add_library('system', 'drupal.ajax');