Commit 7b121564 authored by webchick's avatar webchick

Issue #1947432 by tim.plunkett, mtift, andypost, larowlan: Add a generic...

Issue #1947432 by tim.plunkett, mtift, andypost, larowlan: Add a generic EntityAccessCheck to replace entity_page_access().
parent d2655c9d
......@@ -304,6 +304,10 @@ services:
class: Drupal\Core\Access\DefaultAccessCheck
tags:
- { name: access_check }
access_check.entity:
class: Drupal\Core\Entity\EntityAccessCheck
tags:
- { name: access_check }
maintenance_mode_subscriber:
class: Drupal\Core\EventSubscriber\MaintenanceModeSubscriber
tags:
......
<?php
/**
* @file
* Contains \Drupal\Core\Entity\EntityAccessCheck.
*/
namespace Drupal\Core\Entity;
use Drupal\Core\Entity\EntityInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Access\AccessCheckInterface;
/**
* Provides a generic access checker for entities.
*/
class EntityAccessCheck implements AccessCheckInterface {
/**
* {@inheritdoc}
*/
public function applies(Route $route) {
return array_key_exists('_entity_access', $route->getRequirements());
}
/**
* Implements \Drupal\Core\Access\AccessCheckInterface::access().
*
* The value of the '_entity_access' key must be in the pattern
* 'entity_type.operation.' The entity type must match the {entity_type}
* parameter in the route pattern. This will check a node for 'update' access:
* @code
* pattern: '/foo/{node}/bar'
* requirements:
* _entity_access: 'node.update'
* @endcode
* Available operations are 'view', 'update', 'create', and 'delete'.
*/
public function access(Route $route, Request $request) {
// Split the entity type and the operation.
$requirement = $route->getRequirement('_entity_access');
list($entity_type, $operation) = explode('.', $requirement);
// If there is valid entity of the given entity type, check its access.
if ($request->attributes->has($entity_type)) {
$entity = $request->attributes->get($entity_type);
if ($entity instanceof EntityInterface) {
return $entity->access($operation);
}
}
// No opinion, so other access checks should decide if access should be
// allowed or not.
return NULL;
}
}
<?php
/**
* @file
* Contains Drupal\shortcut\Access\LinkDeleteAccessCheck.
*/
namespace Drupal\shortcut\Access;
use Drupal\Core\Access\AccessCheckInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\HttpFoundation\Request;
/**
* Provides an access check for shortcut link delete routes.
*/
class LinkDeleteAccessCheck implements AccessCheckInterface {
/**
* {@inheritdoc}
*/
public function applies(Route $route) {
return array_key_exists('_access_shortcut_link_delete', $route->getRequirements());
}
/**
* {@inheritdoc}
*/
public function access(Route $route, Request $request) {
$menu_link = $request->attributes->get('menu_link');
$set_name = str_replace('shortcut-', '', $menu_link['menu_name']);
if ($shortcut_set = shortcut_set_load($set_name)) {
return shortcut_set_edit_access($shortcut_set);
}
}
}
<?php
/**
* @file
* Contains \Drupal\shortcut\Form\LinkDelete.
*/
namespace Drupal\shortcut\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\menu_link\Plugin\Core\Entity\MenuLink;
/**
* Builds the shortcut link deletion form.
*/
class LinkDelete extends ConfirmFormBase {
/**
* The menu link to delete.
*
* @var \Drupal\menu_link\Plugin\Core\Entity\MenuLink
*/
protected $menuLink;
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'shortcut_link_delete';
}
/**
* {@inheritdoc}
*/
protected function getQuestion() {
return t('Are you sure you want to delete the shortcut %title?', array('%title' => $this->menuLink->link_title));
}
/**
* {@inheritdoc}
*/
protected function getCancelPath() {
return 'admin/config/user-interface/shortcut/manage/' . $this->menuLink->menu_name;
}
/**
* {@inheritdoc}
*/
protected function getConfirmText() {
return t('Delete');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, MenuLink $menu_link = NULL) {
$this->menuLink = $menu_link;
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
menu_link_delete($this->menuLink->mlid);
$set_name = str_replace('shortcut-', '' , $this->menuLink->menu_name);
$form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $set_name;
drupal_set_message(t('The shortcut %title has been deleted.', array('%title' => $this->menuLink->link_title)));
}
}
<?php
/**
* @file
* Contains \Drupal\shortcut\Form\SetDelete.
*/
namespace Drupal\shortcut\Form;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\ControllerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Database\Connection;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\shortcut\Plugin\Core\Entity\Shortcut;
/**
* Builds the shortcut set deletion form.
*/
class SetDelete extends ConfirmFormBase implements ControllerInterface {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The shortcut set being deleted.
*
* @var \Drupal\shortcut\Plugin\Core\Entity\Shortcut
*/
protected $shortcut;
/**
* Constructs a SetDelete object.
*/
public function __construct(Connection $database, ModuleHandlerInterface $module_handler) {
$this->database = $database;
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database'),
$container->get('module_handler')
);
}
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'shortcut_set_delete_form';
}
/**
* {@inheritdoc}
*/
protected function getQuestion() {
return t('Are you sure you want to delete the shortcut set %title?', array('%title' => $this->shortcut->label()));
}
/**
* {@inheritdoc}
*/
protected function getCancelPath() {
return 'admin/config/user-interface/shortcut/manage/' . $this->shortcut->id();
}
/**
* {@inheritdoc}
*/
protected function getConfirmText() {
return t('Delete');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, Shortcut $shortcut = NULL) {
$this->shortcut = $shortcut;
// Find out how many users are directly assigned to this shortcut set, and
// make a message.
$number = $this->database->query('SELECT COUNT(*) FROM {shortcut_set_users} WHERE set_name = :name', array(':name' => $this->shortcut->id()))->fetchField();
$info = '';
if ($number) {
$info .= '<p>' . format_plural($number,
'1 user has chosen or been assigned to this shortcut set.',
'@count users have chosen or been assigned to this shortcut set.') . '</p>';
}
// Also, if a module implements hook_shortcut_default_set(), it's possible
// that this set is being used as a default set. Add a message about that too.
if ($this->moduleHandler->getImplementations('shortcut_default_set')) {
$info .= '<p>' . t('If you have chosen this shortcut set as the default for some or all users, they may also be affected by deleting it.') . '</p>';
}
$form['info'] = array(
'#markup' => $info,
);
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
$this->shortcut->delete();
$form_state['redirect'] = 'admin/config/user-interface/shortcut';
drupal_set_message(t('The shortcut set %title has been deleted.', array('%title' => $this->shortcut->label())));
}
}
......@@ -20,6 +20,7 @@
* module = "shortcut",
* controllers = {
* "storage" = "Drupal\shortcut\ShortcutStorageController",
* "access" = "Drupal\shortcut\ShortcutAccessController",
* "list" = "Drupal\shortcut\ShortcutListController",
* "form" = {
* "default" = "Drupal\shortcut\ShortcutFormController"
......
<?php
/**
* @file
* Contains \Drupal\shortcut\ShortcutAccessController.
*/
namespace Drupal\shortcut;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityAccessController;
use Drupal\user\Plugin\Core\Entity\User;
/**
* Defines the access controller for the shortcut entity type.
*/
class ShortcutAccessController extends EntityAccessController {
/**
* {@inheritdoc}
*/
public function deleteAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
if (!user_access('administer shortcuts')) {
return FALSE;
}
return $entity->id() != 'default';
}
}
......@@ -53,7 +53,7 @@ public function form(array $form, array &$form_state, EntityInterface $entity) {
protected function actions(array $form, array &$form_state) {
// Disable delete of default shortcut set.
$actions = parent::actions($form, $form_state);
$actions['delete']['#access'] = shortcut_set_delete_access($this->getEntity($form_state));
$actions['delete']['#access'] = $this->getEntity($form_state)->access('delete');
return $actions;
}
......
......@@ -38,7 +38,7 @@ public function getOperations(EntityInterface $entity) {
'options' => $uri['options'],
'weight' => 10,
);
if (shortcut_set_delete_access($entity)) {
if ($entity->access('delete')) {
$operations['delete'] = array(
'title' => t('Delete set'),
'href' => $uri['path'] . '/delete',
......
......@@ -471,113 +471,6 @@ function shortcut_admin_add_link($shortcut_link, &$shortcut_set) {
shortcut_set_reset_link_weights($shortcut_set);
}
/**
* Form callback: builds the confirmation form for deleting a shortcut set.
*
* @param $form
* An associative array containing the structure of the form.
* @param $form_state
* An associative array containing the current state of the form.
* @param $shortcut_set Drupal\shortcut\Plugin\Core\Entity\Shortcut
* An object representing the shortcut set, as returned from
* shortcut_set_load().
*
* @return
* An array representing the form definition.
*
* @ingroup forms
* @see shortcut_set_delete_form_submit()
*/
function shortcut_set_delete_form($form, &$form_state, $shortcut_set) {
$form['shortcut_set'] = array(
'#type' => 'value',
'#value' => $shortcut_set->id(),
);
// Find out how many users are directly assigned to this shortcut set, and
// make a message.
$number = db_query('SELECT COUNT(*) FROM {shortcut_set_users} WHERE set_name = :name', array(':name' => $shortcut_set->id()))->fetchField();
$info = '';
if ($number) {
$info .= '<p>' . format_plural($number,
'1 user has chosen or been assigned to this shortcut set.',
'@count users have chosen or been assigned to this shortcut set.') . '</p>';
}
// Also, if a module implements hook_shortcut_default_set(), it's possible
// that this set is being used as a default set. Add a message about that too.
if (count(module_implements('shortcut_default_set')) > 0) {
$info .= '<p>' . t('If you have chosen this shortcut set as the default for some or all users, they may also be affected by deleting it.') . '</p>';
}
$form['info'] = array(
'#markup' => $info,
);
return confirm_form(
$form,
t('Are you sure you want to delete the shortcut set %title?', array('%title' => $shortcut_set->label())),
'admin/config/user-interface/shortcut/manage/' . $shortcut_set->id(),
t('This action cannot be undone.'),
t('Delete'),
t('Cancel')
);
}
/**
* Submit handler for shortcut_set_delete_form().
*/
function shortcut_set_delete_form_submit($form, &$form_state) {
$shortcut_set = shortcut_set_load($form_state['values']['shortcut_set']);
$label = $shortcut_set->label();
$shortcut_set->delete();
$form_state['redirect'] = 'admin/config/user-interface/shortcut';
drupal_set_message(t('The shortcut set %title has been deleted.', array('%title' => $label)));
}
/**
* Form callback: builds the confirmation form for deleting a shortcut link.
*
* @param $form
* An associative array containing the structure of the form.
* @param $form_state
* An associative array containing the current state of the form.
* @param $shortcut_link
* An array representing the link that will be deleted.
*
* @return
* An array representing the form definition.
*
* @ingroup forms
* @see shortcut_link_delete_submit()
*/
function shortcut_link_delete($form, &$form_state, $shortcut_link) {
$form['shortcut_link'] = array(
'#type' => 'value',
'#value' => $shortcut_link,
);
return confirm_form(
$form,
t('Are you sure you want to delete the shortcut %title?', array('%title' => $shortcut_link['link_title'])),
'admin/config/user-interface/shortcut/manage/' . $shortcut_link['menu_name'],
t('This action cannot be undone.'),
t('Delete'),
t('Cancel')
);
}
/**
* Submit handler for shortcut_link_delete_submit().
*/
function shortcut_link_delete_submit($form, &$form_state) {
$shortcut_link = $form_state['values']['shortcut_link'];
menu_link_delete($shortcut_link['mlid']);
$set_name = str_replace('shortcut-', '' , $shortcut_link['menu_name']);
$form_state['redirect'] = 'admin/config/user-interface/shortcut/manage/' . $set_name;
drupal_set_message(t('The shortcut %title has been deleted.', array('%title' => $shortcut_link['link_title'])));
}
/**
* Menu page callback: creates a new link in the provided shortcut set.
*
......
......@@ -101,11 +101,7 @@ function shortcut_menu() {
);
$items['admin/config/user-interface/shortcut/manage/%shortcut_set/delete'] = array(
'title' => 'Delete shortcut set',
'page callback' => 'drupal_get_form',
'page arguments' => array('shortcut_set_delete_form', 5),
'access callback' => 'shortcut_set_delete_access',
'access arguments' => array(5),
'file' => 'shortcut.admin.inc',
'route_name' => 'shortcut_set_delete',
);
$items['admin/config/user-interface/shortcut/manage/%shortcut_set/add-link'] = array(
'title' => 'Add shortcut',
......@@ -135,11 +131,7 @@ function shortcut_menu() {
);
$items['admin/config/user-interface/shortcut/link/%menu_link/delete'] = array(
'title' => 'Delete shortcut',
'page callback' => 'drupal_get_form',
'page arguments' => array('shortcut_link_delete', 5),
'access callback' => 'shortcut_link_access',
'access arguments' => array(5),
'file' => 'shortcut.admin.inc',
'route_name' => 'shortcut_link_delete',
);
$items['user/%user/shortcuts'] = array(
'title' => 'Shortcuts',
......@@ -199,30 +191,6 @@ function shortcut_set_edit_access($shortcut_set = NULL) {
return FALSE;
}
/**
* Access callback for deleting a shortcut set.
*
* @param $shortcut_set Drupal\shortcut\Plugin\Core\Entity\Shortcut
* The shortcut set to be deleted.
*
* @return
* TRUE if the current user has access to delete shortcut sets and this is
* not the site-wide default set; FALSE otherwise.
*/
function shortcut_set_delete_access($shortcut_set) {
// Only admins can delete sets.
if (!user_access('administer shortcuts')) {
return FALSE;
}
// Never let the default shortcut set be deleted.
if ($shortcut_set->id() == 'default') {
return FALSE;
}
return TRUE;
}
/**
* Access callback for switching the shortcut set assigned to a user account.
*
......
shortcut_link_delete:
pattern: '/admin/config/user-interface/shortcut/link/{menu_link}/delete'
defaults:
_form: 'Drupal\shortcut\Form\LinkDelete'
requirements:
_access_shortcut_link_delete: 'TRUE'
shortcut_set_delete:
pattern: '/admin/config/user-interface/shortcut/manage/{shortcut}/delete'
defaults:
_form: 'Drupal\shortcut\Form\SetDelete'
requirements:
_entity_access: 'shortcut.delete'
services:
access_check.shortcut.link:
class: Drupal\shortcut\Access\LinkDeleteAccessCheck
tags:
- { name: access_check }
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Entity\EntityAccessCheckTest.
*/
namespace Drupal\Tests\Core\Entity;
// @todo Remove once http://drupal.org/node/1620010 is committed.
if (!defined('LANGUAGE_DEFAULT')) {
define('LANGUAGE_DEFAULT', 'und');
}
if (!defined('LANGUAGE_NOT_SPECIFIED')) {
define('LANGUAGE_NOT_SPECIFIED', 'und');
}
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
use Drupal\Core\Entity\EntityAccessCheck;
use Drupal\Tests\UnitTestCase;
/**
* Tests the entity access controller.
*
* @group Entity
*/
class EntityAccessCheckTest extends UnitTestCase {
public static function getInfo() {
return array(
'name' => 'Entity access check test',
'description' => 'Unit test of entity access checking system.',
'group' => 'Entity'
);
}
/**
* Tests the method for checking if the access check applies to a route.
*/
public function testApplies() {
$applies_check = new EntityAccessCheck();
$route = $this->getMockBuilder('Symfony\Component\Routing\Route')
->disableOriginalConstructor()
->getMock();
$route->expects($this->any())
->method('getRequirements')
->will($this->returnValue(array('_entity_access' => '')));
$res = $applies_check->applies($route);
$this->assertEquals(TRUE, $res);
$route = $this->getMockBuilder('Symfony\Component\Routing\Route')
->disableOriginalConstructor()
->getMock();
$route->expects($this->any())
->method('getRequirements')
->will($this->returnValue(array()));
$res = $applies_check->applies($route);
$this->assertEquals(FALSE, $res);
}
/**
* Tests the method for checking access to routes.
*/
public function testAccess() {
$route = new Route('/foo', array(), array('_entity_access' => 'node.update'));
$request = new Request();
$node = $this->getMockBuilder('Drupal\node\Plugin\Core\Entity\Node')
->disableOriginalConstructor()
->getMock();
$node->expects($this->any())
->method('access')
->will($this->returnValue(TRUE));
$access_check = new EntityAccessCheck();
$request->attributes->set('node', $node);
$access = $access_check->access($route, $request);
$this->assertEquals(TRUE, $access);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment