Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / admin_toolbar / admin_toolbar_links_access_filter / admin_toolbar_links_access_filter.module
1 <?php
2
3 /**
4  * @file
5  * This module don't show menu links that you don't have access permission for.
6  */
7
8 use Drupal\Core\Session\AccountInterface;
9 use Drupal\Core\Url;
10 use Drupal\user\Entity\Role;
11 use Symfony\Component\Routing\Exception\RouteNotFoundException;
12 use Drupal\Core\Routing\RouteMatchInterface;
13
14 /**
15  * Implements hook_help().
16  */
17 function admin_toolbar_links_access_filter_help($route_name, RouteMatchInterface $route_match) {
18   switch ($route_name) {
19     // Main module help.
20     case 'help.page.admin_toolbar_links_access_filter':
21       $output = '';
22       $output .= '<h3>' . t('About') . '</h3>';
23       $output .= '<p>' . t('The Admin Toolbar Links Access Filter module provides a workaround for the common problem that users with <em>Use the administration pages and help</em> permission see menu links they done not have access permission for.') . '</p>';
24
25       return $output;
26   }
27 }
28
29 /**
30  * Implements hook_preprocess_menu().
31  *
32  * Hides links from admin menu, if user doesn't have access rights.
33  */
34 function admin_toolbar_links_access_filter_preprocess_menu(&$variables) {
35   if (empty($variables['items'])) {
36     // Additional empty check to prevent exotic situations, where the preprocess
37     // function is entered even without items.
38     // @see https://www.drupal.org/node/2833885
39     return;
40   }
41   // Ensure that menu_name exists.
42   if (!isset($variables['menu_name'])) {
43     // In rare cases (for unknown reasons) menu_name may not be set.
44     // As fallback, we can fetch it from the first menu item.
45     $first_link = reset($variables['items']);
46     /** @var Drupal\Core\Menu\MenuLinkDefault $original_link */
47     // Fetch the menu_name from the original link.
48     $original_link = $first_link['original_link'];
49     $variables['menu_name'] = $original_link->getMenuName();
50   }
51   if ($variables['menu_name'] == 'admin') {
52     if (!admin_toolbar_links_access_filter_user_has_admin_role($variables['user'])) {
53       admin_toolbar_links_access_filter_filter_non_accessible_links($variables['items']);
54     }
55   }
56 }
57
58 /**
59  * Hides links from admin menu, if user doesn't have access rights.
60  */
61 function admin_toolbar_links_access_filter_filter_non_accessible_links(array &$items) {
62   foreach ($items as $route => &$item) {
63     $route_name = $route;
64     $route_params = [];
65     if (!empty($item['original_link'])) {
66       /** @var \Drupal\Core\Menu\MenuLinkBase $original_link */
67       $original_link = $item['original_link'];
68       if ($original_link->getUrlObject()->isExternal()) {
69         // Do not filter external URL at all.
70         continue;
71       }
72       $route_name = $original_link->getRouteName();
73       $route_params = $original_link->getRouteParameters();
74     }
75
76     // Check, if user has access rights to the route.
77     if (!\Drupal::accessManager()->checkNamedRoute($route_name, $route_params)) {
78       unset($items[$route]);
79     }
80     else {
81       if (!empty($items[$route]['below'])) {
82         // Recursively call this function for the child items.
83         admin_toolbar_links_access_filter_filter_non_accessible_links($items[$route]['below']);
84       }
85       if (empty($items[$route]['below']) && \Drupal::moduleHandler()->moduleExists('admin_toolbar')) {
86
87         // Every child item has been cleared out.
88         // Now check, if the given route represents an overview page only,
89         // without having functionality on its own. In this case, we can safely
90         // unset this item, as there aren't any children left.
91         // This assumption is only valid, when the admin_toolbar module is
92         // installed because otherwise we won't have child items at all.
93         if (admin_toolbar_links_access_filter_is_overview_page($route)) {
94           unset($items[$route]);
95         }
96         else {
97           // Let's remove the expanded flag.
98           $items[$route]['is_expanded'] = FALSE;
99         }
100       }
101     }
102   }
103 }
104
105 /**
106  * Implements template_preprocess_admin_block_content().
107  */
108 function admin_toolbar_links_access_filter_admin_block_content(&$variables) {
109   if (!admin_toolbar_links_access_filter_user_has_admin_role($variables['user'])) {
110     foreach ($variables['content'] as $key => &$item) {
111       if (isset($item['url']) && $item['url'] instanceof Url) {
112         /* @var \Drupal\Core\Url $url */
113         $url = $item['url'];
114         if ($url->access()) {
115           continue;
116         }
117         unset($variables['content'][$key]);
118       }
119
120       // The key is structured in the form: "ID title route",
121       // concatenated with spaces.
122       $key_parts = explode(' ', $key);
123       $route = end($key_parts);
124
125       // Special handling for Views pages, as they are not defined
126       // system routes.
127       // @TODO check the permission for Views + find a generic way for similar
128       // cases. Best way would be to get the link entity somehow to properly
129       // check permissions.
130       if (strpos($route, 'views_view:') === 0) {
131         continue;
132       }
133
134       // Check, if user has access rights to the route.
135       if (!\Drupal::accessManager()->checkNamedRoute($route)) {
136         unset($variables['content'][$key]);
137       }
138     }
139   }
140 }
141
142 /**
143  * Checks if the given route name is an overview page.
144  *
145  * Checks if the given route name matches a pure (admin) overview page that can
146  * be skipped, if there are no child items set. The typical example are routes
147  * having the SystemController::systemAdminMenuBlockPage() function as their
148  * controller callback set.
149  *
150  * @param string $route_name
151  *   The route name to check.
152  *
153  * @return bool
154  *   TRUE, if the given route name matches a pure admin overview page route,
155  *   FALSE otherwise.
156  */
157 function admin_toolbar_links_access_filter_is_overview_page($route_name) {
158   // @var \Drupal\Core\Routing\RouteProviderInterface $route_provider.
159   $route_provider = \Drupal::service('router.route_provider');
160   $overview_page_controllers = [
161     '\Drupal\system\Controller\AdminController::index',
162     '\Drupal\system\Controller\SystemController::overview',
163     '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage',
164   ];
165   try {
166     $route = $route_provider->getRouteByName($route_name);
167     $controller = $route->getDefault('_controller');
168     return !empty($controller) && in_array($controller, $overview_page_controllers);
169   }
170   catch (RouteNotFoundException $ex) {
171
172   }
173   return FALSE;
174 }
175
176 /**
177  * Checks, if the given user has admin rights.
178  *
179  * @param \Drupal\Core\Session\AccountInterface $account
180  *   The account to check.
181  *
182  * @return bool
183  *   TRUE, if the given user account has at least one role with admin rights
184  *   assigned, FALSE otherwise.
185  */
186 function admin_toolbar_links_access_filter_user_has_admin_role(AccountInterface $account) {
187   static $user_has_admin_role = [];
188   $uid = $account->id();
189   if (!isset($user_has_admin_role[$uid])) {
190     $roles = Role::loadMultiple($account->getRoles());
191     foreach ($roles as $role) {
192       if ($role->isAdmin()) {
193         $user_has_admin_role[$uid] = TRUE;
194         break;
195       }
196       $user_has_admin_role[$uid] = FALSE;
197     }
198   }
199   return $user_has_admin_role[$uid];
200 }