Score:1

Add a custom Access callback to the profile module to hide the menu tab for certain users

ru flag

We are using the Profile module and I'm trying to hide the menu tab on the user's account for certain users based on a value of a field on the user.

I have the alterRoute set.

namespace Drupal\mymodule\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

/**
 * Listens to the dynamic route events.
 */
class RouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  protected function alterRoutes(RouteCollection $collection) {
    // Change access for path '/user/%/myprofile'.
    if ($route = $collection->get('profile.user_page.single')) {
      $route->setRequirement('_custom_access', 'Drupal\mymodule\Access\ProfileAccessCheck::access');
    }
  }

}

I've created the services in the mymodule.services.yml file.

services:
  mymodule.route_subscriber:
    class: Drupal\mymodule\Routing\RouteSubscriber
    tags:
      - { name: event_subscriber }
  mymodule.profile_access_checker:
    class: Drupal\mymodule\Access\ProfileAccessCheck
    tags:
      - { name: access_check, applies_to: _custom_access }

And here is my ProfileAccessCheck.php

namespace Drupal\mymodule\Access;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\Routing\Route;
use Drupal\user\UserInterface;

/**
 * Checks whether the profile type allows multiple profiles per user.
 */
class ProfileAccessCheck implements AccessInterface {

  /**
   * Checks access for the single/multiple pages.
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The currently logged in account.
   * @param \Drupal\user\UserInterface $user
   *   The user account.
   */
  public function access(AccountInterface $account, $user) {
    $user_access = $user->access('view', $account, TRUE);
    if (!$user_access->isAllowed()) {
      // The account does not have access to the user's canonical page
      // ("/user/{user}"), don't allow access to any sub-pages either.
      return AccessResult::allowed();
    }

    if(!empty($account->field_pro_profile->getValue()) && $account->field_pro_profile->getValue() == 'Disable') {
      return AccessResult::forbidden();
    }
    return AccessResult::allowed();
  }

}

I have a couple of issues. First is, I'm getting this error:

Error: Call to a member function access() on string in Drupal\mymodule\Access\ProfileAccessCheck->access() (line 26 of modules/custom/mymodule/src/Access/ProfileAccessCheck.php).

If I remove that access $user->access line then I get this error:

Notice: Undefined property: Drupal\Core\Session\AccountProxy::$field_pro_profile in Drupal\mymodule\Access\ProfileAccessCheck->access() (line 26 of modules/custom/mymodule/src/Access/ProfileAccessCheck.php).

I'm also getting this error on some other pages like the module enable/disable page /admin/modules:

RuntimeException: Callable "Drupal\mymodule\Access\ProfileAccessCheck::access" requires a value for the "$user" argument. in Drupal\Component\Utility\ArgumentsResolver->handleUnresolvedArgument() (line 142 of core/lib/Drupal/Component/Utility/ArgumentsResolver.php).

Why can't I access the user object, what am I missing? Also, it seems to be overriding the access from the profile module. What is the correct way to make sure I call the original module access function too? Because it does not return tabs if I do AccessResult::neutral(); it hides all tabs that match user/%/%

Jaypan avatar
de flag
I think that the function declaration is incorrect and should probably be: `public function access(UserInterface $user, $profileType) {`.
No Sssweat avatar
ua flag
`public function access(UserInterface $user, AccountInterface $account) {`
ru flag
@Jaypan Yeah I tried that too. It gives me this error. ```RuntimeException: Callable "Drupal\mymodule\Access\ProfileAccessCheck::access" requires a value for the "$profileType" argument. in Drupal\Component\Utility\ArgumentsResolver->handleUnresolvedArgument() (line 142 of core/lib/Drupal/Component/Utility/ArgumentsResolver.php).```
ru flag
@NoSssweat that works! But I can't seem to access the $profileType. I need to check it and make sure it's the correct value in the third argument because it's effecting other user tabs besides the profile. I've tried adding it at different spots and I get this ```RuntimeException: Callable "Drupal\mymodule\Access\ProfileAccessCheck::access" requires a value for the "$profileType" argument. in Drupal\Component\Utility\ArgumentsResolver->handleUnresolvedArgument() (line 142 of core/lib/Drupal/Component/Utility/ArgumentsResolver.php).```
liquidcms avatar
us flag
I have almost identical code for a different problem and this is the access function: public function access(UserInterface $user, AccountInterface $account) { return AccessResult::forbidden(); } and still get the same error: RuntimeException: Callable "Drupal\ssc_custom\Access\CommentReplyAccess::access" requires a value for the "$user" argument.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.