If we defined routes, and users go to those routes, Drupal would check access for us automatically (according to the requirements set forth in the route definition). However, we may often need to check access to a given route programmatically, for example, to know whether we should show a link to it to the current user.
In Chapter 2, Creating Your First Module, we saw how to work with Url objects to create links, and we can use these very Url objects to check access on a given route; consider the following example:
$url = Url::fromRoute('hello_world.hello'); if ($url->access()) { // Do something. }
The access() method on the Url object works only with routed URLs, those which have been determined to have a route behind them. It will obviously not work with things such as external URLs, so, in these cases, it will always return TRUE. Also, we can pass an AccountInterface to this method in case we want to check whether a specific user has access to that route. Without an argument, it defaults to the current user.
Under the hood, the Url class uses the AccessManager service statically to check the access of the route. This is done statically, so if you want, you can inject the service yourself (access_manager) and check the route access:
$access = $accessManager()->checkNamedRoute('hello_world.hello', [], $account)
The empty array we pass as a second argument is an array of parameters that the route needs. You remember how route parameters work from Chapter 2, Creating Your First Module, right?
I mentioned earlier that it's very important to use the account, route, and route match that are being passed to the access checker as dynamic arguments if you need them for calculating the access logic, as opposed to injecting the current user or current route match services and using those. Maybe, now, you can start to understand why. Let me break it down.
One of my earlier points was that an advantage of the service-based access checking approach is that it allows us to use the same service on multiple routes. This means that we can have highly dynamic access rules by which we can check route options within the access checker and calculate access based on those, and this is quite powerful.
However, if you inject the current route match service and make use of that, your access rules will work only when that route is being requested in the browser, so, basically, when the user is trying to go to that path. This is because the current route just happens to be the same as the route the access checker is using (the injected one). However, if you programmatically check access on that route from another page (as we just saw), the current route match will be of that other page instead of the one you actually want to check access to.
You'll see this happen even if you don't manually check access on routes with menu links. If a given route is used in a menu link and printed on a page, Drupal will do the access checking automatically to ensure that users have access to that link. Moreover, recall from Chapter 5, Menus and Menu Links, that if you want to render menu links programmatically, one of the things you'll typically do is run the menu tree through a set of manipulators. An important manipulator is that which checks whether the current user has access to that route.
In these cases, you have the same problem. So, do remember to type hint your access checker with the route and/or route match objects and do not inject them. Of course, do not inject the current user service either (unless you have a very specific reason for doing so).