You are here

final class TeamPermissionHandler in Apigee Edge 8

Provides the available team permissions based on yml files.

To define team permissions you can use a $module.team_permissions.yml file.

If your module needs to define dynamic permissions you can use the permission_providers key to declare a class that implements DynamicTeamPermissionProviderInterface that will return an array of team permissions. Each item in the array can contain the same keys as an entry in $module.team_permissions.yml.

Here is an example (comments have been added):


# The key is the team permission machine name, and is required.
manage team members:
  # (required) The human-readable name of the team permission, to be shown
  # on the team permission administration page.
  title: 'Manage team members'
  # (optional) Additional description for the team permission used in the UI.
  description: 'Add/remove team members.'
  # (optional) The category that the team permission belongs (ex.: Team Apps)
  # to be shown on the team permission administration page.
  # Default is the name of the provider module.
  category: 'Members'

# An array of classes used to generate dynamic team permissions.
permission_providers:
  # Each item in the array must implement
  # DynamicTeamPermissionProviderInterface interface.
  - Drupal\apigee_edge_teams\DefaultTeamPermissionsProvider

Based on Drupal core's PermissionHandler with a bunch of improvements.

Hierarchy

Expanded class hierarchy of TeamPermissionHandler

See also

\Drupal\user\PermissionHandler

\Drupal\apigee_edge_teams\DynamicTeamPermissionProviderInterface

1 string reference to 'TeamPermissionHandler'
apigee_edge_teams.services.yml in modules/apigee_edge_teams/apigee_edge_teams.services.yml
modules/apigee_edge_teams/apigee_edge_teams.services.yml
1 service uses TeamPermissionHandler
apigee_edge_teams.team_permissions in modules/apigee_edge_teams/apigee_edge_teams.services.yml
Drupal\apigee_edge_teams\TeamPermissionHandler

File

modules/apigee_edge_teams/src/TeamPermissionHandler.php, line 72

Namespace

Drupal\apigee_edge_teams
View source
final class TeamPermissionHandler implements TeamPermissionHandlerInterface {
  use StringTranslationTrait;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  private $moduleHandler;

  /**
   * The class resolver.
   *
   * @var \Drupal\Core\DependencyInjection\ClassResolverInterface
   */
  private $classResolver;

  /**
   * The YAML discovery object instance cache.
   *
   * Yaml discovery to find all .team_permissions.yml files.
   *
   * Use getYamlDiscovery() instead.
   *
   * @var \Drupal\Core\Discovery\YamlDiscovery|null
   */
  private $yamlDiscovery;

  /**
   * The team membership manager service.
   *
   * @var \Drupal\apigee_edge_teams\TeamMembershipManagerInterface
   */
  private $teamMembershipManager;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  private $entityTypeManager;

  /**
   * TeamPermissionHandler constructor.
   *
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
   *   The class resolver.
   * @param \Drupal\apigee_edge_teams\TeamMembershipManagerInterface $team_membership_manager
   *   The team membership manager service.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(ModuleHandlerInterface $module_handler, ClassResolverInterface $class_resolver, TeamMembershipManagerInterface $team_membership_manager, EntityTypeManagerInterface $entity_type_manager) {
    $this->moduleHandler = $module_handler;
    $this->classResolver = $class_resolver;
    $this->teamMembershipManager = $team_membership_manager;
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public function getPermissions() : array {
    $all_permissions = $this
      ->buildPermissionsYaml();
    return $this
      ->sortPermissions($all_permissions);
  }

  /**
   * {@inheritdoc}
   */
  public function getDeveloperPermissionsByTeam(TeamInterface $team, AccountInterface $account) : array {
    if ($account
      ->isAnonymous()) {
      throw new InvalidArgumentException('Anonymous user can not be member of a team.');
    }
    $permissions = [];
    try {
      $developer_team_ids = $this->teamMembershipManager
        ->getTeams($account
        ->getEmail());
    } catch (\Exception $e) {
      $developer_team_ids = [];
    }

    // Only add team membership based permissions to the list if the developer
    // is still member of the team in Apigee Edge.
    if (in_array($team
      ->id(), $developer_team_ids)) {

      /** @var \Drupal\apigee_edge_teams\Entity\TeamRoleInterface $member_role */
      $member_role = $this->entityTypeManager
        ->getStorage('team_role')
        ->load(TeamRoleInterface::TEAM_MEMBER_ROLE);
      $permissions += $member_role
        ->getPermissions();

      /** @var \Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface|null $dev_team_role */
      $dev_team_role = $this->entityTypeManager
        ->getStorage('team_member_role')
        ->loadByDeveloperAndTeam($account, $team);
      if ($dev_team_role) {
        foreach ($dev_team_role
          ->getTeamRoles() as $role) {
          $permissions = array_merge($permissions, $role
            ->getPermissions());
        }
      }
    }

    // Allow 3rd-party modules to modify a developer's team-level permissions
    // withing a team.
    // WARNING: Alter hooks gets called even if the developer is not member
    // of a team (company) in Apigee Edge. This allows to grant team-level
    // permissions to a developer (Drupal user) to a team without adding it as a
    // member to the team (company) in Apigee Edge. (Ex.: for team management
    // purposes, etc.)
    $this->moduleHandler
      ->alter('apigee_edge_teams_developer_permissions_by_team', $permissions, $team, $account);
    return array_unique($permissions);
  }

  /**
   * Gets the YAML discovery.
   *
   * @return \Drupal\Core\Discovery\YamlDiscovery
   *   The YAML discovery.
   */
  private function getYamlDiscovery() : YamlDiscovery {
    if (!isset($this->yamlDiscovery)) {
      $this->yamlDiscovery = new YamlDiscovery('team_permissions', $this->moduleHandler
        ->getModuleDirectories());
    }
    return $this->yamlDiscovery;
  }

  /**
   * Builds all team permissions provided by .team_permissions.yml files.
   *
   * @return \Drupal\apigee_edge_teams\Structure\TeamPermission[]
   *   Array of team permissions.
   *
   * @throws \Drupal\apigee_edge_teams\Exception\InvalidArgumentException
   *   If permission provider class does not implement
   *   DynamicTeamPermissionProviderInterface.
   * @throws \InvalidArgumentException
   *   If permission provider class does not exist.
   */
  protected function buildPermissionsYaml() : array {
    $all_permissions = [];
    $all_dynamic_permissions = [];
    $module_names = $this
      ->getModuleNames();
    foreach ($this
      ->getYamlDiscovery()
      ->findAll() as $provider => $permissions) {
      if (isset($permissions['permission_providers'])) {
        foreach ($permissions['permission_providers'] as $fqcn) {

          // Thanks for class resolver permission providers can implement
          // ContainerInjectionInterface and access services. This should be
          // a better approach than what PermissionHandler does with controller
          // resolver.
          $permission_provider = $this->classResolver
            ->getInstanceFromDefinition($fqcn);
          if ($permission_provider instanceof DynamicTeamPermissionProviderInterface) {

            /** @var \Drupal\apigee_edge_teams\Structure\TeamPermission $dynamic_permission */
            foreach ($permission_provider
              ->permissions() as $dynamic_permission) {
              $all_dynamic_permissions[$dynamic_permission
                ->getName()] = $dynamic_permission;
            }
          }
          else {
            throw new InvalidArgumentException(sprintf('%s must implement %s.', $fqcn, DynamicTeamPermissionProviderInterface::class));
          }
        }
        unset($permissions['permission_providers']);
      }
      foreach ($permissions as $name => $permission) {
        if (!is_array($permission)) {
          $permission = [
            'title' => $permission,
          ];
        }
        $permission['name'] = $name;
        $permission['title'] = $this
          ->t($permission['title']);
        $permission['description'] = isset($permission['description']) ? $this
          ->t($permission['description']) : NULL;
        $permission['category'] = !empty($permission['category']) ? $this
          ->t($permission['category']) : $this
          ->t($module_names[$provider]);
        $all_permissions[$name] = $permission;
      }
    }
    return array_map(function (array $permission) {
      return new TeamPermission($permission['name'], $permission['title'], $permission['category'], $permission['description']);
    }, $all_permissions) + $all_dynamic_permissions;
  }

  /**
   * Sorts the given team permissions by category and title.
   *
   * @param array $all_permissions
   *   The team permissions to be sorted.
   *
   * @return \Drupal\apigee_edge_teams\Structure\TeamPermission[]
   *   Sorted team permissions.
   */
  protected function sortPermissions(array $all_permissions = []) {
    uasort($all_permissions, function (TeamPermission $permission_a, TeamPermission $permission_b) {
      if ($permission_a
        ->getCategory() == $permission_b
        ->getCategory()) {
        return $permission_a
          ->getLabel() > $permission_b
          ->getLabel();
      }
      else {
        return $permission_a
          ->getCategory() > $permission_b
          ->getCategory();
      }
    });
    return $all_permissions;
  }

  /**
   * Returns all module names.
   *
   * @return string[]
   *   Returns the human readable names of all modules keyed by machine name.
   */
  protected function getModuleNames() : array {
    $modules = [];
    foreach (array_keys($this->moduleHandler
      ->getModuleList()) as $module) {
      $modules[$module] = $this->moduleHandler
        ->getName($module);
    }
    asort($modules);
    return $modules;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
TeamPermissionHandler::$classResolver private property The class resolver.
TeamPermissionHandler::$entityTypeManager private property The entity type manager.
TeamPermissionHandler::$moduleHandler private property The module handler.
TeamPermissionHandler::$teamMembershipManager private property The team membership manager service.
TeamPermissionHandler::$yamlDiscovery private property The YAML discovery object instance cache.
TeamPermissionHandler::buildPermissionsYaml protected function Builds all team permissions provided by .team_permissions.yml files.
TeamPermissionHandler::getDeveloperPermissionsByTeam public function Returns team permissions of a developer within a team. Overrides TeamPermissionHandlerInterface::getDeveloperPermissionsByTeam
TeamPermissionHandler::getModuleNames protected function Returns all module names.
TeamPermissionHandler::getPermissions public function Gets all available team permissions. Overrides TeamPermissionHandlerInterface::getPermissions
TeamPermissionHandler::getYamlDiscovery private function Gets the YAML discovery.
TeamPermissionHandler::sortPermissions protected function Sorts the given team permissions by category and title.
TeamPermissionHandler::__construct public function TeamPermissionHandler constructor.