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 @@
namespace Drupal\views;
use Drupal\views_ui_listing\EntityListControllerBase;
use Drupal\views_ui_listing\EntityListController;
use Drupal\Core\Entity\EntityInterface;
/**
* Provides a listing of Views.
*/
class ViewListController extends EntityListControllerBase {
public function __construct($entity_type, $entity_info = FALSE) {
parent::__construct($entity_type, $entity_info);
}
class ViewListController extends EntityListController {
/**
* Overrides Drupal\views_ui_listing\EntityListControllerBase::hookMenu();
* Overrides Drupal\views_ui_listing\EntityListController::load();
*/
public function hookMenu() {
// Find the path and the number of path arguments.
$path = $this->entityInfo['list path'];
$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) {
public function load() {
$entities = parent::load();
uasort($entities, function ($a, $b) {
$a_enabled = $a->isEnabled();
$b_enabled = $b->isEnabled();
if ($a_enabled != $b_enabled) {
......@@ -76,14 +28,14 @@ public function getList() {
}
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) {
$operations = $this->buildActionLinks($view);
public function buildRow(EntityInterface $view) {
$operations = $this->buildOperations($view);
$operations['#theme'] = 'links__ctools_dropbutton';
return array(
'data' => array(
......@@ -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(
'view_name' => array(
'data' => t('View name'),
......@@ -119,7 +71,7 @@ public function getHeaderData() {
'data' => t('Path'),
'class' => array('views-ui-path'),
),
'actions' => array(
'operations' => array(
'data' => t('Operations'),
'class' => array('views-ui-operations'),
),
......@@ -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) {
$path = $this->entityInfo['list path'] . '/view/' . $view->id();
$enabled = $view->isEnabled();
public function getOperations(EntityInterface $view) {
$uri = $view->uri();
$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(
'title' => t('Enable'),
'ajax' => TRUE,
'token' => TRUE,
'href' => "$path/enable",
'weight' => -10,
);
}
$definition['edit'] = array(
'title' => t('Edit'),
'href' => "$path/edit",
);
if ($enabled) {
else {
$definition['disable'] = array(
'title' => t('Disable'),
'ajax' => TRUE,
'token' => TRUE,
'href' => "$path/disable",
'weight' => 0,
);
}
// This property doesn't exist yet.
......@@ -158,22 +113,24 @@ public function defineActionLinks(EntityInterface $view) {
$definition['revert'] = array(
'title' => t('Revert'),
'href' => "$path/revert",
'weight' => 5,
);
}
else {
$definition['delete'] = array(
'title' => t('Delete'),
'href' => "$path/delete",
'weight' => 10,
);
}
return $definition;
}
/**
* Overrides Drupal\views_ui_listing\EntityListControllerBase::renderList();
* Overrides Drupal\views_ui_listing\EntityListController::render();
*/
public function renderList() {
$list = parent::renderList();
public function render() {
$list = parent::render();
$list['#attached']['css'] = views_ui_get_admin_css();
return $list;
}
......
......@@ -161,6 +161,16 @@ public function getModule() {
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().
*/
......
......@@ -7,6 +7,7 @@
use Drupal\views\ViewExecutable;
use Drupal\views\ViewUI;
use Drupal\Core\Entity\EntityInterface;
/**
* Implements hook_menu().
......@@ -20,6 +21,12 @@ function views_ui_menu() {
'access arguments' => array('administer views'),
'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).
$items['admin/structure/views/add'] = array(
......@@ -28,6 +35,26 @@ function views_ui_menu() {
'type' => MENU_LOCAL_ACTION,
) + $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).
$items['admin/structure/views/add-template'] = array(
......@@ -752,3 +779,43 @@ function views_ui_truncate($string, $length) {
function views_ui_load($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
/**
* Definition of Drupal\views_ui_listing\EntityListControllerBase.
* @file
* Definition of Drupal\views_ui_listing\EntityListController.
*/
namespace Drupal\views_ui_listing;
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;
/**
* The Config entity type.
* The entity type name.
*
* @var string
*/
protected $entityType;
/**
* The Config entity info.
* The entity info array.
*
* @var array
*
* @see entity_get_info()
*/
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, $entity_info = FALSE) {
public function __construct($entity_type) {
$this->entityType = $entity_type;
$this->storage = entity_get_controller($entity_type);
if (!$entity_info) {
$entity_info = entity_get_info($entity_type);
}
$this->entityInfo = $entity_info;
$this->storage = entity_get_controller($this->entityType);
$this->entityInfo = entity_get_info($this->entityType);
}
/**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::getList();
*/
public function getList() {
return $this->storage->load();
}
/**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::getStorageController();
* Implements Drupal\views_ui_listing\EntityListControllerInterface::getStorageController().
*/
public function getStorageController() {
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() {
$items = array();
$items[$this->entityInfo['list path']] = array(
'page callback' => 'views_ui_listing_entity_listing_page',
'page arguments' => array($this->entityType),
// @todo Add a proper access callback here.
'access callback' => TRUE,
public function getOperations(EntityInterface $entity) {
$uri = $entity->uri();
$operations['edit'] = array(
'title' => t('Edit'),
'href' => $uri['path'] . '/edit',
'options' => $uri['options'],
'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) {
$row = array();
$row['id'] = $entity->id();
$row['label'] = $entity->label();
$actions = $this->buildActionLinks($entity);
$row['actions'] = drupal_render($actions);
return $row;
public function getPath() {
return $this->entityInfo['list path'];
}
/**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::getHeaderData();
* Implements Drupal\views_ui_listing\EntityListControllerInterface::buildHeader().
*/
public function getHeaderData() {
$row = array();
$row['id'] = t('ID');
public function buildHeader() {
$row['label'] = t('Label');
$row['actions'] = t('Actions');
$row['id'] = t('Machine name');
$row['operations'] = t('Operations');
return $row;
}
/**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::buildActionLinks();
* Implements Drupal\views_ui_listing\EntityListControllerInterface::buildRow().
*/
public function buildActionLinks(EntityInterface $entity) {
$links = array();
foreach ($this->defineActionLinks($entity) as $definition) {
$attributes = array();
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,
);
public function buildRow(EntityInterface $entity) {
$row['label'] = $entity->label();
$row['id'] = $entity->id();
$operations = $this->buildOperations($entity);
$row['operations'] = drupal_render($operations);
return $row;
}
/**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::renderList();
* Implements Drupal\views_ui_listing\EntityListControllerInterface::buildOperations().
*/
public function renderList() {
$rows = array();
foreach ($this->getList() as $entity) {
$rows[] = $this->getRowData($entity);
}
// Add core AJAX library if we need to.
if (!empty($this->usesAJAX)) {
drupal_add_library('system', 'drupal.ajax');
}
return array(
'#theme' => 'table',
'#header' => $this->getHeaderData(),
'#rows' => $rows,
'#attributes' => array(
'id' => 'config-entity-listing',
),
public function buildOperations(EntityInterface $entity) {
// Retrieve and sort operations.
$operations = $this->getOperations($entity);
uasort($operations, 'drupal_sort_weight');
$build = array(
'#theme' => 'links',
'#links' => $operations,
);
return $build;
}
/**
* Implements Drupal\views_ui_listing\EntityListControllerInterface::renderList();
* Implements Drupal\views_ui_listing\EntityListControllerInterface::render().
*/
public function renderListAJAX() {
$list = $this->renderList();
$commands = array();
$commands[] = ajax_command_replace('#config-entity-listing', drupal_render($list));
return new JsonResponse(ajax_render($commands));
public function render() {
$build = array(
'#theme' => 'table',
'#header' => $this->buildHeader(),
'#rows' => array(),
'#empty' => t('There is no @label yet. <a href="@add-url">Add one</a>.', array(
'@label' => $this->entityInfo['label'],
'@add-url' => url($this->getPath() . '/add'),
)),
);
foreach ($this->load() as $entity) {
$build['#rows'][$entity->id()] = $this->buildRow($entity);
}
return $build;
}
}
......@@ -10,38 +10,37 @@
use Drupal\Core\Entity\EntityInterface;
/**
* Defines an interface for Configuration entity listing plugins.
* Defines an interface for entity list controllers.
*/
interface EntityListControllerInterface {
/*
* Returns a list of all available config entites of this type.
*/
public function getList();
/**
* Gets the ConfigEntityController.
* Gets the entity storage controller.
*
* @todo Put in correct namespace and docs here.
* @return Drupal\Core\Entity\EntityStorageControllerInterface
* The storage controller used by this list controller.
*/
public function getStorageController();
/**
* Gets the hook_menu array item.
* Loads entities of this type from storage for listing.
*
* @todo Put in correct docs here.
* @return array
* An array of entities implementing Drupal\Core\Entity\EntityInterface.
*/
public function hookMenu();
public function load();
/**
* Builds an array of data for each row.
* Provides an array of information to render the operation links.
*
* @param EntityInterface $entity
* @param Drupal\Core\Entity\EntityInterface $entity
* The entity the operations are for.
*
* @return array
* An array of fields to use for this entity.
* A array of operation link data to use in
* EntityListControllerInterface::buildOperations().
*/
public function getRowData(EntityInterface $entity);
public function getOperations(EntityInterface $entity);
/**
* Builds the header row.
......@@ -49,36 +48,36 @@ public function getRowData(EntityInterface $entity);
* @return array
* An array of header strings.
*/
public function getHeaderData();
public function buildHeader();
/**
* Renders the list page markup to be output.
* Builds an array of data for each row.
*
* @return string
* The output markup for the listing page.
*/
public function renderList();
/**
* Returns the list page as JSON.
* @param Drupal\Core\Entity\EntityInterface $entity
* The entity for this row of the list.
*
* @return Symfony\Component\HttpFoundation\JsonResponse
* AJAX commands to render the list.
* @return array
* An array of fields to use for this entity.
*/
public function renderListAJAX();