apigee_edge-8.x-1.17/modules/apigee_edge_teams/src/TeamMembershipManager.php

modules/apigee_edge_teams/src/TeamMembershipManager.php
<?php

/**
 * Copyright 2018 Google Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

namespace Drupal\apigee_edge_teams;

use Apigee\Edge\Api\ApigeeX\Structure\AppGroupMembership;
use Apigee\Edge\Api\Management\Structure\CompanyMembership;
use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\apigee_edge\Entity\Controller\DeveloperControllerInterface;
use Drupal\apigee_edge\Entity\Controller\EntityCacheAwareControllerInterface;
use Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface;
use Drupal\apigee_edge\Entity\DeveloperCompaniesCacheInterface;
use Drupal\apigee_edge\Exception\DeveloperDoesNotExistException;
use Drupal\user\UserInterface;
use Psr\Log\LoggerInterface;

/**
 * Service that makes easier to work with company/appgroup (team) memberships.
 *
 * It also handles cache invalidation.
 */
final class TeamMembershipManager implements TeamMembershipManagerInterface {

  /**
   * The company members controller factory service.
   *
   * @var \Drupal\apigee_edge_teams\CompanyMembersControllerFactoryInterface
   */
  private $companyMembersControllerFactory;

  /**
   * The appgroup members controller factory service.
   *
   * @var \Drupal\apigee_edge_teams\AppGroupMembersControllerFactoryInterface
   */
  private $appGroupMembersControllerFactory;

  /**
   * The developer companies cache.
   *
   * @var \Drupal\apigee_edge\Entity\DeveloperCompaniesCacheInterface
   */
  private $developerCompaniesCache;

  /**
   * The developer controller service.
   *
   * @var \Drupal\apigee_edge\Entity\Controller\DeveloperControllerInterface
   */
  private $developerController;

  /**
   * The cache tags invalidator service.
   *
   * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface
   */
  private $cacheTagsInvalidator;

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

  /**
   * The logger.
   *
   * @var \Psr\Log\LoggerInterface
   */
  private $logger;

  /**
   * The organization controller service.
   *
   * @var \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface
   */
  private $orgController;

  /**
   * TeamMembershipManager constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager service.
   * @param \Drupal\apigee_edge_teams\CompanyMembersControllerFactoryInterface $company_members_controller_factory
   *   The company members controller factory service.
   * @param \Drupal\apigee_edge_teams\AppGroupMembersControllerFactoryInterface $appgroup_members_controller_factory
   *   The company members controller factory service.
   * @param \Drupal\apigee_edge\Entity\Controller\DeveloperControllerInterface $developer_controller
   *   The developer controller service.
   * @param \Drupal\apigee_edge\Entity\DeveloperCompaniesCacheInterface $developer_companies_cache
   *   The developer companies cache.
   * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_tags_invalidator
   *   The cache tags invalidator service.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger.
   * @param \Drupal\apigee_edge\Entity\Controller\OrganizationControllerInterface $org_controller
   *   The organization controller service.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, CompanyMembersControllerFactoryInterface $company_members_controller_factory, AppGroupMembersControllerFactoryInterface $appgroup_members_controller_factory, DeveloperControllerInterface $developer_controller, DeveloperCompaniesCacheInterface $developer_companies_cache, CacheTagsInvalidatorInterface $cache_tags_invalidator, LoggerInterface $logger, OrganizationControllerInterface $org_controller) {
    $this->entityTypeManager = $entity_type_manager;
    $this->companyMembersControllerFactory = $company_members_controller_factory;
    $this->appGroupMembersControllerFactory = $appgroup_members_controller_factory;
    $this->developerController = $developer_controller;
    $this->developerCompaniesCache = $developer_companies_cache;
    $this->cacheTagsInvalidator = $cache_tags_invalidator;
    $this->logger = $logger;
    $this->orgController = $org_controller;
  }

  /**
   * {@inheritdoc}
   */
  public function syncAppGroupMembers(string $team): array {
    $controller = $this->appGroupMembersControllerFactory->appGroupMembersController($team);
    $members = $controller->syncAppGroupMembers();
    return array_keys($members->getMembers());
  }

  /**
   * {@inheritdoc}
   */
  public function getMembers(string $team): array {
    // Checking for ApigeeX organization.
    if ($this->orgController->isOrganizationApigeeX()) {
      return $this->getAppGroupMembers($team);
    }
    else {
      $controller = $this->companyMembersControllerFactory->companyMembersController($team);
      $members = $controller->getMembers();
      return array_keys($members->getMembers());
    }
  }

  /**
   * Get the AppGroup ApigeeX members email ID and roles.
   *
   * @param string $team
   *   Name of a team.
   */
  private function getAppGroupMembers(string $team): array {
    $controller = $this->appGroupMembersControllerFactory->appGroupMembersController($team);
    $members = $controller->getMembers();
    return array_keys($members->getMembers());
  }

  /**
   * {@inheritdoc}
   */
  public function addMembers(string $team, array $developers): void {
    // Checking for ApigeeX organization.
    if ($this->orgController->isOrganizationApigeeX()) {
      $this->addAppGroupMembers($team, $developers);
    }
    else {
      $membership = new CompanyMembership(array_map(function ($item) {
        return NULL;
      }, array_flip($developers)));
      $controller = $this->companyMembersControllerFactory->companyMembersController($team);
      $controller->setMembers($membership);
      $this->invalidateCaches($team, $developers);
    }
  }

  /**
   * Add the AppGroup ApigeeX members email ID and roles.
   *
   * @param string $team
   *   Name of a team.
   * @param array $developers
   *   Array of developer email addresses.
   */
  private function addAppGroupMembers(string $team, array $developers): void {
    $appGroupMembership = new AppGroupMembership($developers);
    $controller = $this->appGroupMembersControllerFactory->appGroupMembersController($team);
    $controller->setMembers($appGroupMembership);

    $membership = new AppGroupMembership(array_flip(array_keys($developers)));
    $this->invalidateCaches($team, $membership->getMembers());
  }

  /**
   * {@inheritdoc}
   */
  public function removeMembers(string $team, array $developers): void {
    // Checking for ApigeeX organization.
    if ($this->orgController->isOrganizationApigeeX()) {
      $controller = $this->appGroupMembersControllerFactory->appGroupMembersController($team);
    }
    else {
      $controller = $this->companyMembersControllerFactory->companyMembersController($team);
    }
    /** @var \Drupal\apigee_edge_teams\Entity\Storage\TeamMemberRoleStorageInterface $team_member_role_storage */
    $team_member_role_storage = $this->entityTypeManager->getStorage('team_member_role');
    /** @var \Drupal\user\UserInterface[] $users_by_mail */
    $users_by_mail = array_reduce($this->entityTypeManager->getStorage('user')->loadByProperties(['mail' => $developers]), function (array $carry, UserInterface $user) {
      $carry[$user->getEmail()] = $user;
      return $carry;
    }, []);

    foreach ($developers as $developer) {
      $controller->removeMember($developer);
      // Remove team member's roles from Drupal.
      if (array_key_exists($developer, $users_by_mail)) {
        /** @var \Drupal\user\Entity\User $account */
        $account = user_load_by_mail($users_by_mail[$developer]->getEmail());
        $team_entity = $this->entityTypeManager->getStorage('team')->load($team);
        /** @var \Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface[] $team_member_roles_in_team */
        $team_member_roles_in_team = $team_member_role_storage->loadByDeveloperAndTeam($account, $team_entity);
        try {
          if (!empty($team_member_roles_in_team)) {
            $team_member_roles_in_team->delete();
          }
        }
        catch (EntityStorageException $e) {
          $this->logger->critical("Failed to remove %developer team member's roles in %team team with its membership.", [
            '%developer' => $developer,
            '%team' => $team_member_roles_in_team->getTeam()->id(),
          ]);
        }
      }
    }
    $this->invalidateCaches($team, $developers);
  }

  /**
   * {@inheritdoc}
   */
  public function getTeams(string $developer, ?string $team = NULL): array {
    /** @var \Drupal\apigee_edge\Entity\DeveloperInterface $entity */
    $entity = $this->entityTypeManager->getStorage('developer')->load($developer);
    if ($entity === NULL) {
      throw new DeveloperDoesNotExistException($developer);
    }
    // Checking for ApigeeX organization.
    if ($this->orgController->isOrganizationApigeeX()) {
      // If team not available, this could happen when switching
      // the Org and if another Orgs team exist in database.
      if ($team !== NULL) {
        // List developer email ids for a particular team.
        $members = $this->getAppGroupMembers($team);
        // Return the AppGroups/teams where the developer is a member.
        return in_array($developer, $members) ? [$team] : [];
      }
      return [];
    }
    else {
      // Developer entity's getCompanies() method should return the list of
      // companies where the developer is member.
      // @see \Drupal\apigee_edge\Entity\Developer::getCompanies()
      return $entity->getCompanies();
    }
  }

  /**
   * Invalidates caches when membership state changes.
   *
   * @param string $team
   *   Name of a team.
   * @param array $developers
   *   Array of developer email addresses.
   */
  private function invalidateCaches(string $team, array $developers): void {
    // At this point we can assume that team entity exists because earlier
    // API calls have not fail.
    $team_entity = $this->entityTypeManager->getStorage('team')->load($team);
    // This invalidates every occupancies where $team has appeared.
    $tags = $team_entity->getCacheTags();
    // This invalidates cache on team listing page(s) because the list
    // of accessible teams for user(s) has changed.
    // (If we find this too much, later we can tag team listing pages with a
    // "team_list:{$developer_email}" tag and only invalidate those developers'
    // team listing pages whose membership state has changed.)
    $tags = array_merge($tags, $this->entityTypeManager->getDefinition('team')->getListCacheTags());
    $this->cacheTagsInvalidator->invalidateTags($tags);

    // Developer::getCompanies() must return the updated membership information.
    // @see \Drupal\apigee_edge\Entity\Developer::getCompanies()
    $developer_companies_cache_tags = array_map(function (string $developer) {
      return "developer:{$developer}";
    }, $developers);
    $this->developerCompaniesCache->invalidate($developer_companies_cache_tags);
    // Developer controller's cache has to be cleared as well otherwise
    // Developer::getCompanies() reloads the old data from the controller's
    // cache.
    if ($this->developerController instanceof EntityCacheAwareControllerInterface) {
      $this->developerController->entityCache()->removeEntities($developers);
    }
    // Enforce re-evaluation of API product entity access.
    $this->entityTypeManager->getAccessControlHandler('api_product')->resetCache();
    // Prevents circular reference between the services:
    // apigee_edge_teams.team_permissions ->
    // apigee_edge_teams.team_membership_manager ->
    // apigee_edge_teams.team_member_api_product_access_handler.
    // This call is just a helper for us to ensure the static cache of the
    // Team member API Product access handler gets cleared when this method
    // gets called. This is especially useful in testing. So calling
    // \Drupal::service() should be fine.
    \Drupal::service('apigee_edge_teams.team_member_api_product_access_handler')->resetCache();
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc