From 195849b2a47077e00b947f3e4f295a9efa84db7b Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Mon, 24 Jun 2013 17:38:32 +0100
Subject: [PATCH] Issue #1872876 by chx, fubhy, dawehner, alexpott,
 tim.plunkett: Turn role permission assignments into configuration.

---
 core/includes/update.inc                      |  31 ++++
 .../Drupal/block/Tests/BlockInterfaceTest.php |   5 -
 core/modules/comment/comment.module           |  30 ++--
 core/modules/field_ui/field_ui.install        |  22 +--
 .../filter/Tests/FilterDefaultConfigTest.php  |   2 +-
 .../lib/Drupal/node/Tests/NodeAccessTest.php  |   4 +-
 core/modules/node/node.install                |  23 +--
 core/modules/node/node.views_execution.inc    |  16 +-
 .../lib/Drupal/simpletest/WebTestBase.php     |   3 +-
 .../system/Tests/Entity/EntityAccessTest.php  |   2 +-
 .../Tests/Entity/EntityBCDecoratorTest.php    |   2 +-
 .../Tests/Entity/EntityUnitTestBase.php       |   3 +-
 .../system/Tests/Module/UninstallTest.php     |   5 +-
 .../Tests/Upgrade/FieldUIUpgradePathTest.php  |   8 +-
 .../Tests/Upgrade/LanguageUpgradePathTest.php |  10 +-
 core/modules/system/system.install            |  10 +-
 .../lib/Drupal/text/Tests/TextSummaryTest.php |   1 -
 core/modules/translation/translation.install  |   7 +-
 .../user/config/schema/user.schema.yml        |   6 +
 .../config/views.view.user_admin_people.yml   |   2 +-
 .../Drupal/user/Plugin/Core/Entity/Role.php   |  39 +++++
 .../user/Plugin/views/field/Permissions.php   |  66 +++++----
 .../user/Plugin/views/filter/Permissions.php  |  87 +++++++++--
 .../user/lib/Drupal/user/RoleInterface.php    |  41 ++++++
 .../lib/Drupal/user/RoleStorageController.php |   6 -
 .../Drupal/user/Tests/UserPermissionsTest.php |   8 +-
 .../Views/HandlerFieldPermissionTest.php      |  66 +++++++++
 .../Views/HandlerFilterPermissionTest.php     |  97 +++++++++++++
 .../user/Tests/Views/UserUnitTestBase.php     |  96 ++++++++++++
 .../views.view.test_field_permission.yml      | 135 +++++++++++++++++
 .../views.view.test_filter_permission.yml     | 123 ++++++++++++++++
 core/modules/user/user.admin.inc              |   3 +-
 core/modules/user/user.install                | 117 +++++++--------
 core/modules/user/user.module                 | 137 ++++++++----------
 core/modules/user/user.views.inc              |  15 +-
 .../lib/Drupal/views/ManyToOneHelper.php      |   2 +-
 .../views/Tests/Handler/FieldCounterTest.php  | 100 +++++++++++++
 .../views/Tests/Handler/FieldUnitTest.php     |   5 -
 .../views/Tests/Plugin/DisplayPageTest.php    |   1 -
 .../Tests/Plugin/RelationshipJoinTestBase.php |   2 +-
 .../Drupal/views/Tests/ViewExecutableTest.php |   2 +-
 .../views/Tests/ViewPageControllerTest.php    |   1 -
 42 files changed, 1035 insertions(+), 306 deletions(-)
 create mode 100644 core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldPermissionTest.php
 create mode 100644 core/modules/user/lib/Drupal/user/Tests/Views/HandlerFilterPermissionTest.php
 create mode 100644 core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php
 create mode 100644 core/modules/user/tests/modules/user_test_views/test_views/views.view.test_field_permission.yml
 create mode 100644 core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml
 create mode 100644 core/modules/views/lib/Drupal/views/Tests/Handler/FieldCounterTest.php

diff --git a/core/includes/update.inc b/core/includes/update.inc
index 7ccda5adeb97..3659caf178ab 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -1542,3 +1542,34 @@ function update_add_cache_columns($table) {
     ));
   }
 }
+
+/**
+ * Replace permissions during update.
+ *
+ * This function can replace one permission to several or even delete an old
+ * one.
+ *
+ * @param array $replace
+ *   An associative array. The keys are the old permissions the values are lists
+ *   of new permissions. If the list is an empty array, the old permission is
+ *   removed.
+ */
+function update_replace_permissions($replace) {
+  $prefix = 'user.role.';
+  $cut = strlen($prefix);
+  $role_names = Drupal::service('config.storage')->listAll($prefix);
+  foreach ($role_names as $role_name) {
+    $rid = substr($role_name, $cut);
+    $config = Drupal::config("user.role.$rid");
+    $permissions = $config->get('permissions') ?: array();
+    foreach ($replace as $old_permission => $new_permissions) {
+      if (($index = array_search($old_permission, $permissions)) !== FALSE) {
+        unset($permissions[$index]);
+        $permissions = array_unique(array_merge($permissions, $new_permissions));
+      }
+    }
+    $config
+      ->set('permissions', $permissions)
+      ->save();
+  }
+}
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
index e71a14602c11..cd070df91540 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
@@ -23,11 +23,6 @@ public static function getInfo() {
     );
   }
 
-  protected function setUp() {
-    parent::setUp();
-    $this->installSchema('user', 'role_permission');
-  }
-
   /**
    * Test configuration and subsequent form() and build() method calls.
    *
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index b0f71f14a655..a8c7896f8147 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1223,20 +1223,24 @@ function comment_node_update_index(EntityInterface $node, $langcode) {
   $index_comments = &drupal_static(__FUNCTION__);
 
   if ($index_comments === NULL) {
-    // Find and save roles that can 'access comments' or 'search content'.
-    $perms = array('access comments' => array(), 'search content' => array());
-    $result = db_query("SELECT rid, permission FROM {role_permission} WHERE permission IN ('access comments', 'search content')");
-    foreach ($result as $record) {
-      $perms[$record->permission][$record->rid] = $record->rid;
-    }
-
-    // Prevent indexing of comments if there are any roles that can search but
-    // not view comments.
+    // Do not index in the following three cases:
+    // 1. 'Authenticated user' can search content but can't access comments.
+    // 2. 'Anonymous user' can search content but can't access comments.
+    // 3. Any role can search content but can't access comments and access
+    // comments is not granted by the 'authenticated user' role. In this case
+    // all users might have both permissions from various roles but it is also
+    // possible to set up a user to have only search content and so a user
+    // edit could change the security situation so it is not safe to index the
+    // comments.
     $index_comments = TRUE;
-    foreach ($perms['search content'] as $rid) {
-      if (!isset($perms['access comments'][$rid]) && (($rid == DRUPAL_AUTHENTICATED_RID || $rid == DRUPAL_ANONYMOUS_RID) || !isset($perms['access comments'][DRUPAL_AUTHENTICATED_RID]))) {
-        $index_comments = FALSE;
-        break;
+    $roles = Drupal::entityManager()->getStorageController('user_role')->load();
+    $authenticated_can_access = $roles[DRUPAL_AUTHENTICATED_RID]->hasPermission('access comments');
+    foreach ($roles as $rid => $role) {
+      if ($role->hasPermission('search content') && !$role->hasPermission('access comments')) {
+        if ($rid == DRUPAL_AUTHENTICATED_RID || $rid == DRUPAL_ANONYMOUS_RID || !$authenticated_can_access) {
+          $index_comments = FALSE;
+          break;
+        }
       }
     }
   }
diff --git a/core/modules/field_ui/field_ui.install b/core/modules/field_ui/field_ui.install
index c434bb3b63c0..7bc401f1ffe0 100644
--- a/core/modules/field_ui/field_ui.install
+++ b/core/modules/field_ui/field_ui.install
@@ -9,39 +9,29 @@
  * Upgrade Field UI permissions.
  */
 function field_ui_update_8001() {
-
-  $permissions = array(
+  $replace = array(
     'administer comments' => array(
+      'administer comments',
       'administer comment fields',
       'administer comment display',
     ),
     'administer content types' => array(
+      'administer content types',
       'administer node fields',
       'administer node display',
     ),
     'administer users' => array(
+      'administer users',
       'administer user fields',
       'administer user display',
     ),
     'administer taxonomy' => array(
+      'administer taxonomy',
       'administer taxonomy_term fields',
       'administer taxonomy_term display',
     ),
   );
-
-  // We can not call user_permission_get_modules() as that will start
-  // invoking hooks which we can't during update hooks. Directly query
-  // for the permissions and insert them into the database.
-  foreach ($permissions as $old_permission => $new_permissions) {
-    $results = db_query("SELECT rid FROM {role_permission} WHERE permission = :permission", array(':permission' => $old_permission));
-    foreach ($results as $record) {
-      $query = db_insert('role_permission')->fields(array('rid', 'permission', 'module'));
-      foreach ($new_permissions as $new_permission) {
-        $query->values(array($record->rid, $new_permission, 'field_ui'));
-      }
-      $query->execute();
-    }
-  }
+  update_replace_permissions($replace);
 }
 
 /**
diff --git a/core/modules/filter/lib/Drupal/filter/Tests/FilterDefaultConfigTest.php b/core/modules/filter/lib/Drupal/filter/Tests/FilterDefaultConfigTest.php
index ac078e872935..4490b5a2b10c 100644
--- a/core/modules/filter/lib/Drupal/filter/Tests/FilterDefaultConfigTest.php
+++ b/core/modules/filter/lib/Drupal/filter/Tests/FilterDefaultConfigTest.php
@@ -30,7 +30,7 @@ function setUp() {
     // filter_permission() calls into url() to output a link in the description.
     $this->installSchema('system', 'url_alias');
 
-    $this->installSchema('user', array('users_roles', 'role_permission'));
+    $this->installSchema('user', array('users_roles'));
 
     // Install filter_test module, which ships with custom default format.
     $this->installConfig(array('user', 'filter_test'));
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
index 73b3a44af7cb..4a5e0f8b06f0 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
@@ -26,9 +26,7 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
     // Clear permissions for authenticated users.
-    db_delete('role_permission')
-      ->condition('rid', DRUPAL_AUTHENTICATED_RID)
-      ->execute();
+    $this->container->get('config.factory')->get('user.role.' . DRUPAL_AUTHENTICATED_RID)->set('permissions', array())->save();
   }
 
   /**
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index a0a71ff42f45..0c545b39fd66 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -570,6 +570,15 @@ function _update_7000_node_get_types() {
  * @{
  */
 
+/**
+ * Implements hook_update_dependency().
+ */
+function node_update_dependency() {
+  $dependencies['node'][8013] = array(
+    'user' => 8002,
+  );
+}
+
 /**
  * Rename node type language variable names.
  *
@@ -796,15 +805,11 @@ function node_update_8012() {
  * Renames global revision permissions to use the word 'all'.
  */
 function node_update_8013() {
-  $actions = array('view', 'delete', 'revert');
-
-  foreach ($actions as $action) {
-    db_update('role_permission')
-      ->fields(array('permission' => $action . ' all revisions'))
-      ->condition('permission', $action . ' revisions')
-      ->condition('module', 'node')
-      ->execute();
-  }
+  update_replace_permissions(array(
+    'view revisions' => array('view all revisions'),
+    'revert revisions' => array('revert all revisions'),
+    'delete revisions' => array('delete all revisions'),
+  ));
 }
 
 /**
diff --git a/core/modules/node/node.views_execution.inc b/core/modules/node/node.views_execution.inc
index ead87023ac6c..e43690b01fb7 100644
--- a/core/modules/node/node.views_execution.inc
+++ b/core/modules/node/node.views_execution.inc
@@ -30,17 +30,11 @@ function node_views_analyze(ViewExecutable $view) {
         // check for no access control
         $access = $display->getOption('access');
         if (empty($access['type']) || $access['type'] == 'none') {
-          $result = db_select('role_permission', 'p')
-            ->fields('p', array('rid', 'permission'))
-            ->condition('p.rid', array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID), 'IN')
-            ->condition('p.permission', 'access content')
-            ->execute();
-
-          foreach ($result as $role) {
-            $role->safe = TRUE;
-            $roles[$role->rid] = $role;
-          }
-          if (!($roles[DRUPAL_ANONYMOUS_RID]->safe && $roles[DRUPAL_AUTHENTICATED_RID]->safe)) {
+          $anonymous_role = entity_load('user_role', DRUPAL_ANONYMOUS_RID);
+          $anonymous_has_access = $anonymous_role && $anonymous_role->hasPermission('access content');
+          $authenticated_role = entity_load('user_role', DRUPAL_AUTHENTICATED_RID);
+          $authenticated_has_access = $authenticated_role && $authenticated_role->hasPermission('access content');
+          if (!$anonymous_has_access || !$authenticated_has_access) {
             $ret[] = Analyzer::formatMessage(t('Some roles lack permission to access content, but display %display has no access control.', array('%display' => $display->display['display_title'])), 'warning');
           }
           $filters = $display->getOption('filters');
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 8c468726e161..ffc985085c6b 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -560,8 +560,7 @@ protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NUL
       // Grant the specified permissions to the role, if any.
       if (!empty($permissions)) {
         user_role_grant_permissions($role->id(), $permissions);
-
-        $assigned_permissions = db_query('SELECT permission FROM {role_permission} WHERE rid = :rid', array(':rid' => $role->id()))->fetchCol();
+        $assigned_permissions = entity_load('user_role', $role->id())->permissions;
         $missing_permissions = array_diff($permissions, $assigned_permissions);
         if (!$missing_permissions) {
           $this->pass(t('Created permissions: @perms', array('@perms' => implode(', ', $permissions))), t('Role'));
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
index 9733be63e4af..d7782110561f 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
@@ -29,7 +29,7 @@ public static function getInfo() {
 
   function setUp() {
     parent::setUp();
-    $this->installSchema('user', array('role_permission', 'users_roles'));
+    $this->installSchema('user', array('users_roles'));
     $this->installSchema('system', array('variable', 'url_alias'));
     $this->installSchema('language', 'language');
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
index 74c37be91bae..0ba07bc00d2f 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
@@ -31,7 +31,7 @@ public static function getInfo() {
 
   public function setUp() {
     parent::setUp();
-    $this->installSchema('user', array('users_roles', 'users_data', 'role_permission'));
+    $this->installSchema('user', array('users_roles', 'users_data'));
     $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_type', 'node_access'));
     $this->installSchema('comment', array('comment', 'node_comment_statistics'));
   }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
index 5e73dbc6a1f1..664b09c50fa2 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
@@ -36,8 +36,7 @@ public function setUp() {
    *   (optional) The values used to create the entity.
    * @param array $permissions
    *   (optional) Array of permission names to assign to user. The
-   *   role_permission and users_roles tables must be installed before this can
-   *   be used.
+   *   users_roles tables must be installed before this can be used.
    *
    * @return \Drupal\user\Plugin\Core\Entity\User
    *   The created user entity.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php
index 3345d2f7873f..78cecbfe0bdb 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php
@@ -38,8 +38,7 @@ function testUserPermsUninstalled() {
     module_disable(array('module_test'));
     module_uninstall(array('module_test'));
 
-    // Are the perms defined by module_test removed from {role_permission}.
-    $count = db_query("SELECT COUNT(rid) FROM {role_permission} WHERE permission = :perm", array(':perm' => 'module_test perm'))->fetchField();
-    $this->assertEqual(0, $count, 'Permissions were all removed.');
+    // Are the perms defined by module_test removed?
+    $this->assertFalse(user_roles(FALSE, 'module_test perm'), 'Permissions were all removed.');
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUIUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUIUpgradePathTest.php
index 6f4494201a40..4606d3b22691 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUIUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUIUpgradePathTest.php
@@ -65,11 +65,11 @@ function testFieldUIPermissions() {
 
     $role_permissions = user_role_permissions(array($this->normal_role_id, $this->admin_role_id));
     foreach ($permissions as $old_permission => $new_permissions) {
-      $this->assertFalse(isset($role_permissions[$this->normal_role_id][$old_permission]), format_string('%role_name does not have the old %permission permission', array('%role_name' => $this->normal_role_name, '%permission' => $old_permission)));
-      $this->assertTrue(isset($role_permissions[$this->admin_role_id][$old_permission]), format_string('%role_name still has the old %permission permission', array('%role_name' => $this->admin_role_name, '%permission' => $old_permission)));
+      $this->assertFalse(in_array($old_permission, $role_permissions[$this->normal_role_id]), format_string('%role_name does not have the old %permission permission', array('%role_name' => $this->normal_role_name, '%permission' => $old_permission)));
+      $this->assertTrue(in_array($old_permission, $role_permissions[$this->admin_role_id]), format_string('%role_name still has the old %permission permission', array('%role_name' => $this->admin_role_name, '%permission' => $old_permission)));
       foreach ($new_permissions as $new_permission) {
-        $this->assertFalse(isset($role_permissions[$this->normal_role_id][$new_permission]), format_string('%role_name does not have the new %permission permission', array('%role_name' => $this->normal_role_name, '%permission' => $new_permission)));
-        $this->assertTrue(isset($role_permissions[$this->admin_role_id][$new_permission]), format_string('%role_name has the new %permission permission', array('%role_name' => $this->admin_role_name, '%permission' => $new_permission)));
+        $this->assertFalse(in_array($new_permission, $role_permissions[$this->normal_role_id]), format_string('%role_name does not have the new %permission permission', array('%role_name' => $this->normal_role_name, '%permission' => $new_permission)));
+        $this->assertTrue(in_array($new_permission, $role_permissions[$this->admin_role_id]), format_string('%role_name has the new %permission permission', array('%role_name' => $this->admin_role_name, '%permission' => $new_permission)));
       }
     }
   }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
index ba62946b1a66..506ec4cf075c 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
@@ -191,6 +191,8 @@ public function testLanguageNoPluralsUpgrade() {
    * Tests upgrading translations permissions.
    */
   public function testLanguagePermissionsUpgrade() {
+    // Insert a permission into the Drupal 7 database before running the
+    // upgrade.
     db_insert('role_permission')->fields(array(
       'rid' => 2,
       'permission' => 'translate content',
@@ -198,12 +200,8 @@ public function testLanguagePermissionsUpgrade() {
     ))->execute();
 
     $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
-
-    // Check that translate content role doesn't exist on database.
-    $old_permission_exists = db_query('SELECT * FROM {role_permission} WHERE permission LIKE ?', array('translate content'))->fetchObject();
-    $this->assertFalse($old_permission_exists, 'No translate content role left on database.');
+    $this->assertFalse(user_roles(FALSE, 'translate content'), 'No translate content role left in config.');
     // Check that translate content has been renamed to translate all content.
-    $new_permission_exists = db_query('SELECT * FROM {role_permission} WHERE permission LIKE ?', array('translate all content'))->fetchObject();
-    $this->assertTrue($new_permission_exists, 'Rename role translate content to translate all content was completed successfully.');
+    $this->assertTrue(user_roles(FALSE, 'translate all content'), 'Rename role translate content to translate all content was completed successfully.');
   }
 }
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index d3b67eba7aac..f10d86b2dbac 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1520,13 +1520,9 @@ function system_update_8020() {
   $blocked_ips_exists = db_query_range('SELECT 1 FROM {blocked_ips}', 0, 1)->fetchField();
   if ($blocked_ips_exists) {
     // Rename the permission name.
-    db_update('role_permission')
-      ->fields(array(
-        'permission' => 'ban IP addresses',
-        'module' => 'ban',
-      ))
-      ->condition('permission', 'block IP addresses')
-      ->execute();
+    update_replace_permissions(array(
+      'block IP addresses' => array('ban IP addresses'),
+    ));
     // Rename {blocked_ips} table into {ban_ip}.
     db_rename_table('blocked_ips', 'ban_ip');
     // Remove all references to the removed action callback.
diff --git a/core/modules/text/lib/Drupal/text/Tests/TextSummaryTest.php b/core/modules/text/lib/Drupal/text/Tests/TextSummaryTest.php
index aec92e048635..b287a624ee10 100644
--- a/core/modules/text/lib/Drupal/text/Tests/TextSummaryTest.php
+++ b/core/modules/text/lib/Drupal/text/Tests/TextSummaryTest.php
@@ -28,7 +28,6 @@ function setUp() {
     parent::setUp();
 
     $this->installSchema('system', 'url_alias');
-    $this->installSchema('user', 'role_permission');
     $this->installConfig(array('text'));
   }
 
diff --git a/core/modules/translation/translation.install b/core/modules/translation/translation.install
index 61d014d2e65d..ad15ba07a1c5 100644
--- a/core/modules/translation/translation.install
+++ b/core/modules/translation/translation.install
@@ -10,10 +10,9 @@
  * Rename the translate content permission.
  */
 function translation_update_8000() {
-  db_update('role_permission')
-    ->fields(array('permission' => 'translate all content'))
-    ->condition('permission', 'translate content')
-    ->execute();
+  update_replace_permissions(array(
+    'translate content' => array('translate all content'),
+  ));
 }
 
 /**
diff --git a/core/modules/user/config/schema/user.schema.yml b/core/modules/user/config/schema/user.schema.yml
index 989abaeb4c13..05155ff3472c 100644
--- a/core/modules/user/config/schema/user.schema.yml
+++ b/core/modules/user/config/schema/user.schema.yml
@@ -131,6 +131,12 @@ user.role.*:
     weight:
       type: integer
       label: 'User role weight'
+    permissions:
+      type: sequence
+      label: 'Permissions'
+      sequence:
+        - type: string
+          label: 'Permission'
     langcode:
       type: string
       label: 'Default language'
diff --git a/core/modules/user/config/views.view.user_admin_people.yml b/core/modules/user/config/views.view.user_admin_people.yml
index efaca3c7273d..90c17e19a5c5 100644
--- a/core/modules/user/config/views.view.user_admin_people.yml
+++ b/core/modules/user/config/views.view.user_admin_people.yml
@@ -742,7 +742,7 @@ display:
           plugin_id: user_roles
         permission:
           id: permission
-          table: role_permission
+          table: users_roles
           field: permission
           relationship: none
           group_type: group
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php
index 8d1bf0a696bb..d35d7f16d372 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php
@@ -67,6 +67,13 @@ class Role extends ConfigEntityBase implements RoleInterface {
    */
   public $weight;
 
+  /**
+   * The permissions belonging to this role.
+   *
+   * @var array
+   */
+  public $permissions = array();
+
   /**
    * {@inheritdoc}
    */
@@ -80,6 +87,38 @@ public function uri() {
     );
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getPermissions() {
+    return $this->permissions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasPermission($permission) {
+    return in_array($permission, $this->permissions);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function grantPermission($permission) {
+    if (!$this->hasPermission($permission)) {
+      $this->permissions[] = $permission;
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function revokePermission($permission) {
+    $this->permissions = array_diff($this->permissions, array($permission));
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/field/Permissions.php b/core/modules/user/lib/Drupal/user/Plugin/views/field/Permissions.php
index 34bedd8a1c2e..6bee40cb5f78 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/field/Permissions.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/field/Permissions.php
@@ -8,7 +8,8 @@
 namespace Drupal\user\Plugin\views\field;
 
 use Drupal\Component\Annotation\PluginID;
-use Drupal\Core\Database\Connection;
+use Drupal\Core\Entity\EntityManager;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\field\PrerenderList;
@@ -24,11 +25,18 @@
 class Permissions extends PrerenderList {
 
   /**
-   * Database Service Object.
+   * The role storage controller.
    *
-   * @var \Drupal\Core\Database\Connection
+   * @var \Drupal\user\RoleStorageControllerInterface
    */
-  protected $database;
+  protected $roleStorageController;
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
 
   /**
    * Constructs a Drupal\Component\Plugin\PluginBase object.
@@ -39,20 +47,23 @@ class Permissions extends PrerenderList {
    *   The plugin_id for the plugin instance.
    * @param array $plugin_definition
    *   The plugin implementation definition.
-   * @param \Drupal\Core\Database\Connection $database
-   *   Database Service Object.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager
    */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, Connection $database) {
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, ModuleHandlerInterface $module_handler, EntityManager $entity_manager) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
-    $this->database = $database;
+    $this->roleStorageController = $entity_manager->getStorageController('user_role');
+    $this->moduleHandler = $module_handler;
   }
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
-    return new static($configuration, $plugin_id, $plugin_definition, $container->get('database'));
+    return new static($configuration, $plugin_id, $plugin_definition, $container->get('module_handler'), $container->get('plugin.manager.entity'));
   }
 
   /**
@@ -73,27 +84,32 @@ public function preRender(&$values) {
     $uids = array();
     $this->items = array();
 
+    $permission_names = \Drupal::moduleHandler()->invokeAll('permission');
+
+    $rids = array();
     foreach ($values as $result) {
-      $uids[] = $this->getValue($result);
-    }
+      $user_rids = $this->getEntity($result)->getRoles();
+      $uid = $this->getValue($result);
 
-    if ($uids) {
-      // Get a list of all the modules implementing a hook_permission() and sort by
-      // display name.
-      $module_info = system_get_info('module');
-      $modules = array();
-      foreach (module_implements('permission') as $module) {
-        $modules[$module] = $module_info[$module]['name'];
+      foreach ($user_rids as $rid) {
+        $rids[$rid][] = $uid;
       }
-      asort($modules);
-
-      $permissions = module_invoke_all('permission');
+    }
 
-      $result = $this->database->query('SELECT u.uid, u.rid, rp.permission FROM {role_permission} rp INNER JOIN {users_roles} u ON u.rid = rp.rid WHERE u.uid IN (:uids) AND rp.module IN (:modules) ORDER BY rp.permission',
-        array(':uids' => $uids, ':modules' => array_keys($modules)));
+    if ($rids) {
+      $roles = $this->roleStorageController->load(array_keys($rids));
+      foreach ($rids as $rid => $role_uids) {
+        foreach ($roles[$rid]->getPermissions() as $permission) {
+          foreach ($role_uids as $uid) {
+            $this->items[$uid][$permission]['permission'] = $permission_names[$permission]['title'];
+          }
+        }
+      }
 
-      foreach ($result as $perm) {
-        $this->items[$perm->uid][$perm->permission]['permission'] = $permissions[$perm->permission]['title'];
+      foreach ($uids as $uid) {
+        if (isset($this->items[$uid])) {
+          ksort($this->items[$uid]);
+        }
       }
     }
   }
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/filter/Permissions.php b/core/modules/user/lib/Drupal/user/Plugin/views/filter/Permissions.php
index 4d1aa28850b7..6d763fa01029 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/filter/Permissions.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/filter/Permissions.php
@@ -8,7 +8,10 @@
 namespace Drupal\user\Plugin\views\filter;
 
 use Drupal\Component\Annotation\PluginID;
+use Drupal\Component\Utility\String;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\views\Plugin\views\filter\ManyToOne;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Filter handler for user roles.
@@ -19,25 +22,83 @@
  */
 class Permissions extends ManyToOne {
 
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * Constructs a Permissions object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, ModuleHandlerInterface $module_handler) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->moduleHandler = $module_handler;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
+    return new static($configuration, $plugin_id, $plugin_definition, $container->get('module_handler'));
+  }
+
   public function getValueOptions() {
-    $module_info = system_get_info('module');
+    if (!isset($this->value_options)) {
+      $module_info = system_get_info('module');
 
-    // Get a list of all the modules implementing a hook_permission() and sort by
-    // display name.
-    $modules = array();
-    foreach (module_implements('permission') as $module) {
-      $modules[$module] = $module_info[$module]['name'];
-    }
-    asort($modules);
+      // Get a list of all the modules implementing a hook_permission() and sort by
+      // display name.
+      $modules = array();
+      foreach ($this->moduleHandler->getImplementations('permission') as $module) {
+        $modules[$module] = $module_info[$module]['name'];
+      }
+      asort($modules);
 
-    $this->value_options = array();
-    foreach ($modules as $module => $display_name) {
-      if ($permissions = module_invoke($module, 'permission')) {
-        foreach ($permissions as $perm => $perm_item) {
-          $this->value_options[$display_name][$perm] = check_plain(strip_tags($perm_item['title']));
+      $this->value_options = array();
+      foreach ($modules as $module => $display_name) {
+        if ($permissions = $this->moduleHandler->invoke($module, 'permission')) {
+          foreach ($permissions as $perm => $perm_item) {
+            $this->value_options[$display_name][$perm] = String::checkPlain(strip_tags($perm_item['title']));
+          }
         }
       }
     }
+    else {
+      return $this->value_options;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * Replace the configured permission with a filter by all roles that have this
+   * permission.
+   */
+  public function query() {
+    // @todo user_role_names() should maybe support multiple permissions.
+    $rids = array();
+    // Get all roles, that have the configured permissions.
+    foreach ($this->value as $permission) {
+      $roles = user_role_names(FALSE, $permission);
+      $rids += array_keys($roles);
+    }
+    $rids = array_unique($rids);
+    $this->value = $rids;
+
+    // $this->value contains the role IDs that have the configured permission.
+    parent::query();
   }
 
 }
diff --git a/core/modules/user/lib/Drupal/user/RoleInterface.php b/core/modules/user/lib/Drupal/user/RoleInterface.php
index f503ecc6f73a..b6b749d0dcf5 100644
--- a/core/modules/user/lib/Drupal/user/RoleInterface.php
+++ b/core/modules/user/lib/Drupal/user/RoleInterface.php
@@ -14,4 +14,45 @@
  */
 interface RoleInterface extends ConfigEntityInterface {
 
+  /**
+   * Returns a list of permissions assigned to the role.
+   *
+   * @return array
+   *   The permissions assigned to the role.
+   */
+  public function getPermissions();
+
+  /**
+   * Checks if the role has a permission.
+   *
+   * @param string $permission
+   *   The permission to check for.
+   *
+   * @return bool
+   *   TRUE if the role has the permission, FALSE if not.
+   */
+  public function hasPermission($permission);
+
+  /**
+   * Grant permissions to the role.
+   *
+   * @param string $permission
+   *   The permission to grant.
+   *
+   * @return RoleInterface
+   *   The called object for chaining.
+   */
+  public function grantPermission($permission);
+
+  /**
+   * Revokes a permissions from the user role.
+   *
+   * @param string $permission
+   *   The permission to revoke.
+   *
+   * @return RoleInterface
+   *   The called object for chaining.
+   */
+  public function revokePermission($permission);
+
 }
diff --git a/core/modules/user/lib/Drupal/user/RoleStorageController.php b/core/modules/user/lib/Drupal/user/RoleStorageController.php
index 4b6ca87d2ec6..fff106e932f0 100644
--- a/core/modules/user/lib/Drupal/user/RoleStorageController.php
+++ b/core/modules/user/lib/Drupal/user/RoleStorageController.php
@@ -19,20 +19,14 @@ class RoleStorageController extends ConfigStorageController implements RoleStora
    */
   public function resetCache(array $ids = NULL) {
     parent::resetCache($ids);
-
     // Clear the user access cache.
     drupal_static_reset('user_access');
-    drupal_static_reset('user_role_permissions');
   }
 
   /**
    * {@inheritdoc}
    */
   public function deleteRoleReferences(array $rids) {
-    // Delete permission assignments.
-    db_delete('role_permission')
-      ->condition('rid', $rids)
-      ->execute();
     // Remove the role from all users.
     db_delete('users_roles')
       ->condition('rid', $rids)
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
index 3fc3b4b64020..3c8cd548ba37 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Tests;
 
 use Drupal\simpletest\WebTestBase;
+use Drupal\user\RoleStorageController;
 
 class UserPermissionsTest extends WebTestBase {
   protected $admin_user;
@@ -46,8 +47,8 @@ function testUserPermissionChanges() {
     $edit[$rid . '[administer nodes]'] = TRUE;
     $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
     $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
-    drupal_static_reset('user_access');
-    drupal_static_reset('user_role_permissions');
+    $storage_controller = $this->container->get('plugin.manager.entity')->getStorageController('user_role');
+    $storage_controller->resetCache();
     $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
 
     // Remove a permission.
@@ -56,8 +57,7 @@ function testUserPermissionChanges() {
     $edit[$rid . '[access user profiles]'] = FALSE;
     $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
     $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
-    drupal_static_reset('user_access');
-    drupal_static_reset('user_role_permissions');
+    $storage_controller->resetCache();
     $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
   }
 
diff --git a/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldPermissionTest.php b/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldPermissionTest.php
new file mode 100644
index 000000000000..70e772ad6755
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldPermissionTest.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Tests\Views\HandlerFieldPermissionTest.
+ */
+
+namespace Drupal\user\Tests\Views;
+
+use Drupal\views\Tests\ViewTestData;
+use Drupal\views\Tests\ViewUnitTestBase;
+
+/**
+ * Tests the permission field handler.
+ *
+ * @see \Drupal\user\Plugin\views\field\Permissions
+ */
+class HandlerFieldPermissionTest extends UserUnitTestBase {
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = array('test_field_permission');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'User: Permissions Field',
+      'description' => 'Tests the permission field handler.',
+      'group' => 'Views module integration',
+    );
+  }
+
+  /**
+   * Tests the permission field handler output.
+   */
+  public function testFieldPermission() {
+    $this->setupPermissionTestData();
+
+    $view = views_get_view('test_field_permission');
+    $this->executeView($view);
+    $view->initStyle();
+    $view->render();
+    $style_plugin = $view->style_plugin;
+
+    $expected_permissions = array();
+    $expected_permissions[$this->users[0]->id()] = array();
+    $expected_permissions[$this->users[1]->id()] = array();
+    $expected_permissions[$this->users[2]->id()][] = t('Administer permissions');
+    // View user profiles comes first, because we sort by the permission
+    // machine name.
+    $expected_permissions[$this->users[3]->id()][] = t('Administer permissions');
+    $expected_permissions[$this->users[3]->id()][] = t('Administer users');
+    $expected_permissions[$this->users[3]->id()][] = t('View user profiles');
+
+    foreach ($view->result as $index => $row) {
+      $uid = $view->field['uid']->getValue($row);
+      $rendered_permission = $style_plugin->getField($index, 'permission');
+
+      $expected_output = implode(', ', $expected_permissions[$uid]);
+      $this->assertEqual($rendered_permission, $expected_output, 'The right permissions are rendered.');
+    }
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFilterPermissionTest.php b/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFilterPermissionTest.php
new file mode 100644
index 000000000000..ed67b16ca103
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFilterPermissionTest.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Tests\Views\HandlerFilterPermissionTest.
+ */
+
+namespace Drupal\user\Tests\Views;
+
+use Drupal\Component\Utility\String;
+use Drupal\user\Tests\Views\UserUnitTestBase;
+
+/**
+ * Tests the permissions filter handler.
+ *
+ * @see \Drupal\user\Plugin\views\filter\Permissions
+ */
+class HandlerFilterPermissionTest extends UserUnitTestBase {
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = array('test_filter_permission');
+
+  protected $columnMap;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'User: Permissions Filter',
+      'description' => 'Tests the permission filter handler.',
+      'group' => 'Views module integration',
+    );
+  }
+
+  /**
+   * Tests the permission filter handler.
+   *
+   * @todo Fix the different commented out tests by fixing the many to one
+   *   handler handling with the NOT operator.
+   */
+  public function testFilterPermission() {
+    $this->setupPermissionTestData();
+
+    $column_map = array('uid' => 'uid');
+    $view = views_get_view('test_filter_permission');
+
+    // Filter by a non existing permission.
+    $view->initHandlers();
+    $view->filter['permission']->value = array('non_existent_permission');
+    $this->executeView($view);
+    $this->assertEqual(count($view->result), 4, 'A non existent permission is not filtered so everything is the result.');
+    $expected[] = array('uid' => 1);
+    $expected[] = array('uid' => 2);
+    $expected[] = array('uid' => 3);
+    $expected[] = array('uid' => 4);
+    $this->assertIdenticalResultset($view, $expected, $column_map);
+    $view->destroy();
+
+    // Filter by a permission.
+    $view->initHandlers();
+    $view->filter['permission']->value = array('administer permissions');
+    $this->executeView($view);
+    $this->assertEqual(count($view->result), 2);
+    $expected = array();
+    $expected[] = array('uid' => 3);
+    $expected[] = array('uid' => 4);
+    $this->assertIdenticalResultset($view, $expected, $column_map);
+    $view->destroy();
+
+    // Filter by another permission of a role with multiple permissions.
+    $view->initHandlers();
+    $view->filter['permission']->value = array('administer users');
+    $this->executeView($view);
+    $this->assertEqual(count($view->result), 1);
+    $expected = array();
+    $expected[] = array('uid' => 4);
+    $this->assertIdenticalResultset($view, $expected, $column_map);
+    $view->destroy();
+
+    $view->initDisplay();
+    $view->initHandlers();
+    $view->filter['permission']->getValueOptions();
+
+    // Test the value options.
+    $value_options = $view->filter['permission']->getValueOptions();
+    foreach (array('system' => 'System', 'user' => 'User') as $module => $title) {
+      $expected = array_map(function ($permission) {
+        return String::checkPlain(strip_tags($permission['title']));
+      }, $this->container->get('module_handler')->invoke($module, 'permission'));
+
+      $this->assertEqual($expected, $value_options[$title], 'Ensure the all permissions are available');
+    }
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php b/core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php
new file mode 100644
index 000000000000..9350338787cc
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Tests\Views\UserUnitTestBase.
+ */
+
+namespace Drupal\user\Tests\Views;
+
+use Drupal\views\Tests\ViewTestData;
+use Drupal\views\Tests\ViewUnitTestBase;
+
+/**
+ * Provides a common test base for user views tests.
+ */
+abstract class UserUnitTestBase extends ViewUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('user_test_views', 'user', 'system', 'field');
+
+  /**
+   * Users to use during this test.
+   *
+   * @var array
+   */
+  protected $users = array();
+
+  /**
+   * The entity storage controller for roles.
+   *
+   * @var \Drupal\user\RoleStorageController
+   */
+  protected $roleStorageController;
+
+  /**
+   * The entity storage controller for users.
+   *
+   * @var \Drupal\user\UserStorageController
+   */
+  protected $userStorageController;
+
+  protected function setUp() {
+    parent::setUp();
+
+    ViewTestData::importTestViews(get_class($this), array('user_test_views'));
+
+    $this->installSchema('user', array('users', 'users_roles'));
+    $this->installSchema('system', 'sequences');
+
+    $entity_manager = $this->container->get('plugin.manager.entity');
+    $this->roleStorageController = $entity_manager->getStorageController('user_role');
+    $this->userStorageController = $entity_manager->getStorageController('user');
+  }
+
+  /**
+   * Set some test data for permission related tests.
+   */
+  protected function setupPermissionTestData() {
+    // Setup a role without any permission.
+    $this->roleStorageController->create(array('id' => 'authenticated'))
+      ->save();
+    $this->roleStorageController->create(array('id' => 'no_permission'))
+      ->save();
+    // Setup a role with just one permission.
+    $this->roleStorageController->create(array('id' => 'one_permission'))
+      ->save();
+    user_role_grant_permissions('one_permission', array('administer permissions'));
+    // Setup a role with multiple permissions.
+    $this->roleStorageController->create(array('id' => 'multiple_permissions'))
+      ->save();
+    user_role_grant_permissions('multiple_permissions', array('administer permissions', 'administer users', 'access user profiles'));
+
+    // Setup a user without an extra role.
+    $this->users[] = $account = $this->userStorageController->create(array());
+    $account->save();
+    // Setup a user with just the first role (so no permission beside the
+    // ones from the authenticated role).
+    $this->users[] = $account = $this->userStorageController->create(array('name' => 'first_role'));
+    $account->addRole('no_permission');
+    $account->save();
+    // Setup a user with just the second role (so one additional permission).
+    $this->users[] = $account = $this->userStorageController->create(array('name' => 'second_role'));
+    $account->addRole('one_permission');
+    $account->save();
+    // Setup a user with both the second and the third role.
+    $this->users[] = $account = $this->userStorageController->create(array('name' => 'second_third_role'));
+    $account->addRole('one_permission');
+    $account->addRole('multiple_permissions');
+    $account->save();
+  }
+
+}
diff --git a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_field_permission.yml b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_field_permission.yml
new file mode 100644
index 000000000000..94f587dc69f6
--- /dev/null
+++ b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_field_permission.yml
@@ -0,0 +1,135 @@
+base_field: uid
+base_table: users
+core: 8.x
+description: ''
+status: '1'
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: ''
+    display_options:
+      access:
+        type: none
+      cache:
+        type: none
+      query:
+        type: views_query
+      exposed_form:
+        type: basic
+      pager:
+        type: full
+      style:
+        type: default
+      row:
+        type: fields
+      fields:
+        uid:
+          id: uid
+          table: users
+          field: uid
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Uid
+          exclude: '0'
+          alter:
+            alter_text: '0'
+            text: ''
+            make_link: '0'
+            path: ''
+            absolute: '0'
+            external: '0'
+            replace_spaces: '0'
+            path_case: none
+            trim_whitespace: '0'
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: '0'
+            max_length: ''
+            word_boundary: '1'
+            ellipsis: '1'
+            more_link: '0'
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: '0'
+            trim: '0'
+            preserve_tags: ''
+            html: '0'
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: '1'
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: '1'
+          empty: ''
+          hide_empty: '0'
+          empty_zero: '0'
+          hide_alter_empty: '1'
+          link_to_user: '0'
+          plugin_id: user
+        permission:
+          id: permission
+          table: users_roles
+          field: permission
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Permission
+          exclude: '0'
+          alter:
+            alter_text: '0'
+            text: ''
+            make_link: '0'
+            path: ''
+            absolute: '0'
+            external: '0'
+            replace_spaces: '0'
+            path_case: none
+            trim_whitespace: '0'
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: '0'
+            max_length: ''
+            word_boundary: '1'
+            ellipsis: '1'
+            more_link: '0'
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: '0'
+            trim: '0'
+            preserve_tags: ''
+            html: '0'
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: '1'
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: '1'
+          empty: ''
+          hide_empty: '0'
+          empty_zero: '0'
+          hide_alter_empty: '1'
+          type: separator
+          separator: ', '
+          plugin_id: user_permissions
+      filters: {  }
+      sorts: {  }
+human_name: test_field_permission
+module: views
+id: test_field_permission
+tag: ''
+langcode: en
diff --git a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml
new file mode 100644
index 000000000000..ef1fd1c33b36
--- /dev/null
+++ b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml
@@ -0,0 +1,123 @@
+base_field: uid
+base_table: users
+core: 8.x
+description: ''
+status: '1'
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: ''
+    display_options:
+      access:
+        type: none
+      cache:
+        type: none
+      query:
+        type: views_query
+      exposed_form:
+        type: basic
+      pager:
+        type: full
+      style:
+        type: default
+      row:
+        type: fields
+      fields:
+        uid:
+          id: uid
+          table: users
+          field: uid
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: '0'
+          alter:
+            alter_text: '0'
+            text: ''
+            make_link: '0'
+            path: ''
+            absolute: '0'
+            external: '0'
+            replace_spaces: '0'
+            path_case: none
+            trim_whitespace: '0'
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: '0'
+            max_length: ''
+            word_boundary: '1'
+            ellipsis: '1'
+            more_link: '0'
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: '0'
+            trim: '0'
+            preserve_tags: ''
+            html: '0'
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: '0'
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: '1'
+          empty: ''
+          hide_empty: '0'
+          empty_zero: '0'
+          hide_alter_empty: '1'
+          link_to_user: '0'
+          plugin_id: user
+      filters:
+        permission:
+          id: permission
+          table: users_roles
+          field: permission
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: or
+          value:
+            'access user profiles': 'access user profiles'
+          group: '1'
+          exposed: '0'
+          expose:
+            operator_id: '0'
+            label: ''
+            description: ''
+            use_operator: '0'
+            operator: ''
+            identifier: ''
+            required: '0'
+            remember: '0'
+            multiple: '0'
+            remember_roles:
+              authenticated: authenticated
+            reduce: '0'
+          is_grouped: '0'
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: '1'
+            widget: select
+            multiple: '0'
+            remember: '0'
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          reduce_duplicates: '1'
+          plugin_id: user_permissions
+      sorts: {  }
+human_name: test_filter_permission
+module: views
+id: test_filter_permission
+tag: ''
+langcode: en
diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index f9982e849279..c406b1019a2e 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -105,7 +105,6 @@ function user_admin_account() {
  * @see theme_user_admin_permissions()
  */
 function user_admin_permissions($form, $form_state, $rid = NULL) {
-
   // Retrieve role names for columns.
   $role_names = user_role_names();
   if (isset($rid)) {
@@ -158,7 +157,7 @@ function user_admin_permissions($form, $form_state, $rid = NULL) {
         );
         foreach ($role_names as $rid => $name) {
           // Builds arrays for checked boxes for each role
-          if (isset($role_permissions[$rid][$perm])) {
+          if (in_array($perm, $role_permissions[$rid])) {
             $status[$rid][] = $perm;
           }
         }
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index 293a45e570b9..361a3e44c06f 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -149,42 +149,6 @@ function user_schema() {
     ),
   );
 
-  $schema['role_permission'] = array(
-    'description' => 'Stores the permissions assigned to user roles.',
-    'fields' => array(
-      'rid' => array(
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-        'description' => 'Foreign Key: {role}.rid.',
-      ),
-      'permission' => array(
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'A single permission granted to the role identified by rid.',
-      ),
-      'module' => array(
-        'type' => 'varchar',
-        'length' => DRUPAL_EXTENSION_NAME_MAX_LENGTH,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => "The module declaring the permission.",
-      ),
-    ),
-    'primary key' => array('rid', 'permission'),
-    'indexes' => array(
-      'permission' => array('permission'),
-    ),
-    'foreign keys' => array(
-      'role' => array(
-        'table' => 'role',
-        'columns' => array('rid' => 'rid'),
-      ),
-    ),
-  );
-
   $schema['users_data'] = array(
     'description' => 'Stores module data as key/value pairs per user.',
     'fields' => array(
@@ -386,6 +350,7 @@ function user_update_dependencies() {
   return $dependencies;
 }
 
+
 /**
  * @addtogroup updates-7.x-to-8.x
  * @{
@@ -451,9 +416,6 @@ function user_update_8002() {
   );
   db_change_field('role', 'rid', 'rid', $column);
 
-  $column['description'] = 'Foreign Key: {role}.rid.';
-  db_change_field('role_permission', 'rid', 'rid', $column);
-
   $column['description'] = 'Primary Key: {role}.rid for role.';
   db_change_field('users_roles', 'rid', 'rid', $column);
 
@@ -470,32 +432,16 @@ function user_update_8002() {
   db_drop_unique_key('role', 'name');
 
   // Rename the built-in serial role IDs into the hardcoded machine names.
-  db_update('role')
-    ->fields(array('rid' => DRUPAL_ANONYMOUS_RID))
-    ->condition('rid', 1)
-    ->execute();
-  db_update('role')
-    ->fields(array('rid' => DRUPAL_AUTHENTICATED_RID))
-    ->condition('rid', 2)
-    ->execute();
-
-  db_update('role_permission')
-    ->fields(array('rid' => DRUPAL_ANONYMOUS_RID))
-    ->condition('rid', 1)
-    ->execute();
-  db_update('role_permission')
-    ->fields(array('rid' => DRUPAL_AUTHENTICATED_RID))
-    ->condition('rid', 2)
-    ->execute();
-
-  db_update('users_roles')
-    ->fields(array('rid' => DRUPAL_ANONYMOUS_RID))
-    ->condition('rid', 1)
-    ->execute();
-  db_update('users_roles')
-    ->fields(array('rid' => DRUPAL_AUTHENTICATED_RID))
-    ->condition('rid', 2)
-    ->execute();
+  foreach (array(1, 2) as $rid) {
+    db_update('role')
+      ->fields(array('rid' => _user_update_map_rid($rid)))
+      ->condition('rid', $rid)
+      ->execute();
+    db_update('users_roles')
+      ->fields(array('rid' => _user_update_map_rid($rid)))
+      ->condition('rid', $rid)
+      ->execute();
+  }
 }
 
 /**
@@ -1087,6 +1033,47 @@ function user_update_8018() {
   }
 }
 
+/**
+ * Maps a role id to the new string.
+ *
+ * @param int $rid
+ *   A D7 numeric role ID.
+ *
+ * @return string
+ *   A D8 string role ID.
+ */
+function _user_update_map_rid($rid) {
+  $rid_map = array(
+    1 => DRUPAL_ANONYMOUS_RID,
+    2 => DRUPAL_AUTHENTICATED_RID,
+  );
+  return isset($rid_map[$rid]) ? $rid_map[$rid] : $rid;
+}
+
+/**
+ * Migrate roles permissions into configuration.
+ *
+ * @ingroup config_upgrade
+ */
+function user_update_8019() {
+  $db_permissions = db_select('role_permission', 'p')
+    ->fields('p')
+    ->execute()
+    ->fetchAll();
+  $new_permissions = array();
+  foreach ($db_permissions as $permission) {
+    $rid = _user_update_map_rid($permission->rid);
+    if (!isset($new_permissions[$rid]) || !in_array($permission->permission, $new_permissions[$rid])) {
+      $new_permissions[$rid][] = $permission->permission;
+    }
+  }
+  foreach ($new_permissions as $rid => $permissions) {
+    config("user.role.$rid")
+      ->set('permissions', $permissions)
+      ->save();
+  }
+}
+
 /**
  * @} End of "addtogroup updates-7.x-to-8.x".
  */
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index e7ee37af26bf..a5e6e238dfe8 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -4,12 +4,10 @@
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Session\AccountInterface;
-use Drupal\comment\Plugin\Core\Entity\Comment;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\file\Plugin\Core\Entity\File;
 use Drupal\user\Plugin\Core\Entity\User;
 use Drupal\user\UserInterface;
-use Drupal\user\UserRole;
 use Drupal\user\RoleInterface;
 use Drupal\Core\Template\Attribute;
 use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -410,44 +408,44 @@ function user_password($length = 10) {
 /**
  * Determine the permissions for one or more roles.
  *
- * @param $roles
- *   An array whose values are the role IDs of interest, such as $user->roles.
+ * @param array $roles
+ *   An array of role IDs.
  *
- * @return
- *   An array indexed by role ID. Each value is an array whose keys are the
- *   permission strings for the given role ID.
+ * @return array
+ *   An array indexed by role ID. Each value is an array of permission strings
+ *   for the given role.
  */
-function user_role_permissions($roles) {
-  $cache = &drupal_static(__FUNCTION__, array());
-
-  $role_permissions = $fetch = array();
-
+function user_role_permissions(array $roles) {
+  if (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update') {
+    return _user_role_permissions_update($roles);
+  }
+  $entities = entity_load_multiple('user_role', $roles);
+  $role_permissions = array();
   foreach ($roles as $rid) {
-    if (isset($cache[$rid])) {
-      $role_permissions[$rid] = $cache[$rid];
-    }
-    else {
-      // Add this rid to the list of those needing to be fetched.
-      $fetch[] = $rid;
-      // Prepare in case no permissions are returned.
-      $cache[$rid] = array();
-    }
+    $role_permissions[$rid] = isset($entities[$rid]) ? $entities[$rid]->getPermissions() : array();
   }
+  return $role_permissions;
+}
 
-  if ($fetch) {
-    // Get from the database permissions that were not in the static variable.
-    // Only role IDs with at least one permission assigned will return rows.
-    $result = db_query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch));
-
-    foreach ($result as $row) {
-      $cache[$row->rid][$row->permission] = TRUE;
-    }
-    foreach ($fetch as $rid) {
-      // For every rid, we know we at least assigned an empty array.
-      $role_permissions[$rid] = $cache[$rid];
-    }
+/**
+ * Determine the permissions for one or more roles during update.
+ *
+ * A separate version is needed because during update the entity system can't
+ * be used and in non-update situations the entity system is preferred because
+ * of the hook system.
+ *
+ * @param array $roles
+ *   An array of role IDs.
+ *
+ * @return array
+ *   An array indexed by role ID. Each value is an array of permission strings
+ *   for the given role.
+ */
+function _user_role_permissions_update($roles) {
+  $role_permissions = array();
+  foreach ($roles as $rid) {
+    $role_permissions[$rid] = Drupal::config("user.role.$rid")->get('permissions') ?: array();
   }
-
   return $role_permissions;
 }
 
@@ -490,13 +488,10 @@ function user_access($string, AccountInterface $account = NULL) {
   }
   $perm = &$drupal_static_fast['perm'];
   if (!isset($perm[$account->uid])) {
-    $role_permissions = user_role_permissions($account->getRoles());
-
-    $perms = array();
-    foreach ($role_permissions as $one_role) {
-      $perms += $one_role;
+    $perm[$account->uid] = array();
+    foreach (user_role_permissions($account->getRoles()) as $role_permissions) {
+      $perm[$account->uid] += array_fill_keys($role_permissions, TRUE);
     }
-    $perm[$account->uid] = $perms;
   }
 
   return isset($perm[$account->uid][$string]);
@@ -1759,7 +1754,7 @@ function user_mail_tokens(&$replacements, $data, $options) {
  *   value.
  */
 function user_role_names($membersonly = FALSE, $permission = NULL) {
-  return array_map(function($item) {
+  return array_map(function ($item) {
     return $item->label();
   }, user_roles($membersonly, $permission));
 }
@@ -1844,12 +1839,9 @@ function user_roles($membersonly = FALSE, $permission = NULL) {
   }
 
   if (!empty($permission)) {
-    $result = db_select('role_permission', 'p')
-      ->fields('p', array('rid'))
-      ->condition('p.rid', array_keys($roles))
-      ->condition('p.permission', $permission)
-      ->execute()->fetchCol();
-    $roles = array_intersect_key($roles, array_flip($result));
+    $roles = array_filter($roles, function ($role) use ($permission) {
+      return $role->hasPermission($permission);
+    });
   }
 
   if (empty($permission)) {
@@ -1944,23 +1936,14 @@ function user_role_change_permissions($rid, array $permissions = array()) {
  * @see user_role_revoke_permissions()
  */
 function user_role_grant_permissions($rid, array $permissions = array()) {
-  $modules = user_permission_get_modules();
   // Grant new permissions for the role.
-  foreach ($permissions as $name) {
-    db_merge('role_permission')
-      ->key(array(
-        'rid' => $rid,
-        'permission' => $name,
-      ))
-      ->fields(array(
-        'module' => $modules[$name],
-      ))
-      ->execute();
+  $role = entity_load('user_role', $rid);
+  foreach ($permissions as $permission) {
+    $role->grantPermission($permission);
   }
-
+  $role->save();
   // Clear the user access cache.
   drupal_static_reset('user_access');
-  drupal_static_reset('user_role_permissions');
 }
 
 /**
@@ -1976,14 +1959,13 @@ function user_role_grant_permissions($rid, array $permissions = array()) {
  */
 function user_role_revoke_permissions($rid, array $permissions = array()) {
   // Revoke permissions for the role.
-  db_delete('role_permission')
-    ->condition('rid', $rid)
-    ->condition('permission', $permissions, 'IN')
-    ->execute();
-
+  $role = entity_load('user_role', $rid);
+  foreach ($permissions as $permission) {
+    $role->revokePermission($permission);
+  }
+  $role->save();
   // Clear the user access cache.
   drupal_static_reset('user_access');
-  drupal_static_reset('user_role_permissions');
 }
 
 function user_multiple_cancel_confirm($form, &$form_state) {
@@ -2143,18 +2125,20 @@ function user_build_filter_query(SelectInterface $query) {
     // the authenticated role. If so, then all users would be listed, and we can
     // skip adding it to the filter query.
     if ($key == 'permission') {
-      $account = entity_create('user', array(
-        'uid' => 'user_filter',
-        'roles' => array(DRUPAL_AUTHENTICATED_RID),
-      ));
-      if (user_access($value, $account)) {
+      $roles = user_roles(FALSE, $value);
+      if (isset($roles[DRUPAL_AUTHENTICATED_RID])) {
         continue;
       }
-      $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
-      $permission_alias = $query->join('role_permission', 'p', $users_roles_alias . '.rid = %alias.rid');
-      $query->condition($permission_alias . '.permission', $value);
+      if (!empty($roles)) {
+        $value = array_keys($roles);
+      }
+      else {
+        // There's no role that has this permission set value to an impossible
+        // rid so that no users are matched.
+        $value = array('');
+      }
     }
-    elseif ($key == 'role') {
+    if ($key == 'permission' || $key == 'role') {
       $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
       $query->condition($users_roles_alias . '.rid' , $value);
     }
@@ -2427,9 +2411,6 @@ function user_modules_installed($modules) {
  * Implements hook_modules_uninstalled().
  */
 function user_modules_uninstalled($modules) {
-   db_delete('role_permission')
-     ->condition('module', $modules, 'IN')
-     ->execute();
   // Remove any potentially orphan module data stored for users.
   drupal_container()->get('user.data')->delete($modules);
 }
diff --git a/core/modules/user/user.views.inc b/core/modules/user/user.views.inc
index 0cc88ce42a37..83474b094e5d 100644
--- a/core/modules/user/user.views.inc
+++ b/core/modules/user/user.views.inc
@@ -359,19 +359,7 @@ function user_views_data() {
     ),
   );
 
-  // Define the base group of this table. Fields that don't have a group defined
-  // will go into this field by default.
-  $data['role_permission']['table']['group']  = t('User');
-  // Explain how this table joins to others.
-  $data['role_permission']['table']['join'] = array(
-    'users' => array(
-      'left_table' => 'users_roles',
-      'left_field' => 'rid',
-      'field' => 'rid',
-    ),
-  );
-
-  $data['role_permission']['permission'] = array(
+  $data['users_roles']['permission'] = array(
     'title' => t('Permission'),
     'help' => t('The user permissions.'),
     'field' => array(
@@ -380,6 +368,7 @@ function user_views_data() {
     ),
     'filter' => array(
       'id' => 'user_permissions',
+      'real field' => 'rid',
     ),
   );
 
diff --git a/core/modules/views/lib/Drupal/views/ManyToOneHelper.php b/core/modules/views/lib/Drupal/views/ManyToOneHelper.php
index 24ef8ab13974..ccd3c3b27f47 100644
--- a/core/modules/views/lib/Drupal/views/ManyToOneHelper.php
+++ b/core/modules/views/lib/Drupal/views/ManyToOneHelper.php
@@ -309,7 +309,7 @@ public function addFilter() {
       else {
         $placeholder = $this->placeholder();
         if (count($this->handler->value) > 1) {
-          $this->query->addWhereExpression(0, "$field $operator($placeholder)", array($placeholder => $value));
+          $this->handler->query->addWhereExpression(0, "$field $operator($placeholder)", array($placeholder => $value));
         }
         else {
           $this->handler->query->addWhereExpression(0, "$field $operator $placeholder", array($placeholder => $value));
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldCounterTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldCounterTest.php
new file mode 100644
index 000000000000..87732485d458
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldCounterTest.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\views\Tests\Handler\FieldCounterTest.
+ */
+
+namespace Drupal\views\Tests\Handler;
+
+use Drupal\views\Tests\ViewUnitTestBase;
+
+/**
+ * Tests the Drupal\views\Plugin\views\field\Counter handler.
+ */
+class FieldCounterTest extends ViewUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('user');
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = array('test_view');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Field: Counter',
+      'description' => 'Tests the Drupal\views\Plugin\views\field\Counter handler.',
+      'group' => 'Views Handlers',
+    );
+  }
+
+  function testSimple() {
+    $view = views_get_view('test_view');
+    $view->setDisplay();
+    $view->displayHandlers->get('default')->overrideOption('fields', array(
+      'counter' => array(
+        'id' => 'counter',
+        'table' => 'views',
+        'field' => 'counter',
+        'relationship' => 'none',
+      ),
+      'name' => array(
+        'id' => 'name',
+        'table' => 'views_test_data',
+        'field' => 'name',
+        'relationship' => 'none',
+      ),
+    ));
+    $view->preview();
+
+    $counter = $view->style_plugin->getField(0, 'counter');
+    $this->assertEqual($counter, 1, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 1, '@counter' => $counter)));
+    $counter = $view->style_plugin->getField(1, 'counter');
+    $this->assertEqual($counter, 2, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 2, '@counter' => $counter)));
+    $counter = $view->style_plugin->getField(2, 'counter');
+    $this->assertEqual($counter, 3, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 3, '@counter' => $counter)));
+    $view->destroy();
+
+    $view->setDisplay();
+    $rand_start = rand(5, 10);
+    $view->displayHandlers->get('default')->overrideOption('fields', array(
+      'counter' => array(
+        'id' => 'counter',
+        'table' => 'views',
+        'field' => 'counter',
+        'relationship' => 'none',
+        'counter_start' => $rand_start
+      ),
+      'name' => array(
+        'id' => 'name',
+        'table' => 'views_test_data',
+        'field' => 'name',
+        'relationship' => 'none',
+      ),
+    ));
+    $view->preview();
+
+    $counter = $view->style_plugin->getField(0, 'counter');
+    $expected_number = 0 + $rand_start;
+    $this->assertEqual($counter, $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
+    $counter = $view->style_plugin->getField(1, 'counter');
+    $expected_number = 1 + $rand_start;
+    $this->assertEqual($counter, $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
+    $counter = $view->style_plugin->getField(2, 'counter');
+    $expected_number = 2 + $rand_start;
+    $this->assertEqual($counter, $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
+  }
+
+  // @TODO: Write tests for pager.
+  function testPager() {
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php
index 2c90c37d14be..eff89294d3dc 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php
@@ -38,11 +38,6 @@ public static function getInfo() {
     );
   }
 
-  public function setUp() {
-    parent::setUp();
-    $this->installSchema('user', 'role_permission');
-  }
-
   /**
    * Overrides Drupal\views\Tests\ViewTestBase::viewsData().
    */
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php
index 2ea84d4bcf69..049795c8fdf6 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php
@@ -60,7 +60,6 @@ protected function setUp() {
     $this->installSchema('system', 'router');
     $this->installSchema('system', 'url_alias');
     $this->installSchema('system', 'menu_router');
-    $this->installSchema('user', 'role_permission');
   }
 
   /**
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php
index 172678d3e757..95a543fa0b23 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php
@@ -26,7 +26,7 @@ abstract class RelationshipJoinTestBase extends PluginUnitTestBase {
    * Overrides \Drupal\views\Tests\ViewUnitTestBase::setUpFixtures().
    */
   protected function setUpFixtures() {
-    $this->installSchema('user', array('users', 'users_roles', 'role_permission'));
+    $this->installSchema('user', array('users', 'users_roles'));
     $this->installConfig(array('user'));
     parent::setUpFixtures();
 
diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
index b46840fbac79..894363d19b57 100644
--- a/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
@@ -80,7 +80,7 @@ public static function getInfo() {
   }
 
   protected function setUpFixtures() {
-    $this->installSchema('user', array('users', 'role_permission'));
+    $this->installSchema('user', array('users'));
     $this->installSchema('node', array('node_type', 'node', 'node_field_data'));
     $this->installSchema('comment', array('comment', 'node_comment_statistics'));
     parent::setUpFixtures();
diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php
index d937aea64c21..72da113f0f1b 100644
--- a/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php
@@ -56,7 +56,6 @@ protected function setUp() {
     parent::setUp();
 
     $this->installSchema('system', 'menu_router');
-    $this->installSchema('user', 'role_permission');
 
     $this->pageController = new ViewPageController($this->container->get('plugin.manager.entity')->getStorageController('view'), new ViewExecutableFactory());
   }
-- 
GitLab