Can't get access control handler to be picked up

Created on 26 September 2023, over 1 year ago
Updated 13 November 2023, over 1 year ago

I cannot get my custom access handler to be picked up. Here is my services file:

services:
  group.relation_handler.access_control.pod:
    class: 'Drupal\pod\Plugin\Group\RelationHandler\PodAccessControl'
    shared: false
    arguments:
      - '@group.relation_handler.access_control'

And here is my handler:


namespace Drupal\pod\Plugin\Group\RelationHandler;


use Drupal\Core\Session\AccountInterface;
use Drupal\group\Entity\GroupRelationshipInterface;
use Drupal\group\Plugin\Group\RelationHandler\AccessControlInterface;
use Drupal\group\Plugin\Group\RelationHandler\AccessControlTrait;

/**
 * Provides group access control for the pod module.
 */
class PodAccessControl implements AccessControlInterface {

  use AccessControlTrait;

  /**
   * Constructs a PodAccessControl instance.
   *
   * @param \Drupal\group\Plugin\Group\RelationHandler\AccessControlInterface $parent
   *   The default access control handler.
   */
  public function __construct(AccessControlInterface $parent) {
    $this->parent = $parent;
  }

  /**
   * {@inheritdoc}
   */
  public function relationshipAccess(GroupRelationshipInterface $group_relationship, $operation, AccountInterface $account, $return_as_object = FALSE) {

  }

}

I have cleared my registry, and my class is never instantiated (determined through use of a PHP debugger).

Can anyone provide a pointer as to what I am missing?

## Edit ##

I can see that I need to name my service as an existing relationship handler type. I want to add an access control handler to the group_content_menu relationship type (provided by the Group Content Menu module). So I think I need to maybe decorate the existing access handler for that class, except one doesn't exist in that module, so it us using the Empty class.

My use case is that I want to add the default 'home' link to a Group Content Menu menu, but hide the menu if/when there is only that single link. I am intending to hide the menu by denying access if it only has a home link.

## Edit 2 ##

I've tried every combination of trying to decorate the service that I can think of, according to decoration seen in other modules, but I still cannot figure out how to get my custom access_check service to be called. I'm not sure if I am going down the wrong rabbit hole with this service decoration, but it seems to be maybe the solution. The problem I get is that the service group.relation_handler.access_control.group_menu_content.inner is undefined. So should I be passing group.relation_handler.access_control.inner?

💬 Support request
Status

Active

Version

3.2

Component

Code

Created by

🇨🇦Canada jaypan Victoria, BC

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @jaypan
  • 🇨🇦Canada jaypan Victoria, BC
  • 🇨🇦Canada jaypan Victoria, BC
  • 🇨🇭Switzerland berdir Switzerland

    Here's how I defined a operation provider for gnode, which doesn't have one by default:

      group.relation_handler.operation_provider.group_node:
        class: 'Drupal\MYMODULE\Plugin\Group\RelationHandler\MYCLASSNAME'
        arguments: [ '@group.relation_handler.operation_provider', '@current_user', '@string_translation']
        shared: false
    

    So you provide the default for parent, not inner. the inner stuff is when you decorate an existing service. That said, you likely don't want to decorate even then, because that assumes you want to extend what it does, when it's more likely that you want to replace it anyway.

    To replace an existing definition, you switch the class in a service provider alter:

        if ($container->has('group.relation_handler.operation_provider.group_media')) {
          $definition = $container->getDefinition('group.relation_handler.operation_provider.group_media');
          $definition->setClass(MyCLassName::class);
        }
    

    If you have different constructor arguments, you might need to alter that as well.

    Just throwing this in here for now, we should improve https://www.drupal.org/node/3222292 to document that there.

  • 🇨🇦Canada jaypan Victoria, BC

    Thanks Berdir. I have switched the class in a service alterer, and I can see with a debugger that my alteration is executed:

    
    namespace Drupal\pod;
    
    use Drupal\Core\DependencyInjection\ContainerBuilder;
    use Drupal\Core\DependencyInjection\ServiceProviderBase;
    use Drupal\pod\Plugin\Group\RelationHandler\PodAccessControl;
    
    /**
     * Modifies the language manager service.
     */
    class PodServiceProvider extends ServiceProviderBase {
    
      /**
       * {@inheritdoc}
       */
      public function alter(ContainerBuilder $container) {
        if ($container->has('group.relation_handler.access_control.group_content_menu')) {
          $definition = $container->getDefinition('group.relation_handler.access_control.group_content_menu');
          $definition->setClass(PodAccessControl::class);
        }
    
      }
    
    }
    

    However, my PodAccessControl class is never even accessed (again, using a debugger), even though I can see the group content menu on the page.

    Adding a debug breakpoint to this line: https://git.drupalcode.org/project/group/-/blame/3.0.x/src/GroupServiceP...

    I can see that the callback class for the service is listed as "Drupal\group\Plugin\Group\RelationHandler\EmptyAccessControl". Also, this is only ever called on cache clear (not when accessing the group), and that this code is called BEFORE my container alter service class is invoked, which is why my class is not picked up.

    Any ideas?

  • 🇨🇭Switzerland piridium

    I have a custom daterange field for the relations user <-> group and node <-> group. A custom module only grants access to group nodes if both dateranges include todays date. Like this, we can provide time restricted access to dynamic content.

    I was using a hook_content_info_alter to add a custom access handler class. For 2.0 compatibility, I had to change that and after a lot of headache, I got it running with a service decorator like described here: https://gist.github.com/adamfranco/5814eba660cbda3c93b5253b28b325ab

    I am only changing the access handler for the 'view' operation. Everything else is handled via the existing functionality (roles etc.).

    Am I right that in this case, a decoration like the example in the link above is the correct way to go?

Production build 0.71.5 2024