billwerk_subscriptions-1.x-dev/modules/billwerk_subscriptions_handler_default/src/EventSubscriber/SubscriberRefreshUserSubscriber.php

modules/billwerk_subscriptions_handler_default/src/EventSubscriber/SubscriberRefreshUserSubscriber.php
<?php

declare(strict_types=1);

namespace Drupal\billwerk_subscriptions_handler_default\EventSubscriber;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\billwerk_subscriptions\BillwerkRolesManager;
use Drupal\billwerk_subscriptions\DataObject\BillwerkContractSubscription;
use Drupal\billwerk_subscriptions\Environment;
use Drupal\billwerk_subscriptions\Event\SubscriberRefreshUserEvent;
use Drupal\billwerk_subscriptions\Exception\SubscriberException;
use Drupal\billwerk_subscriptions\LogHelper;
use Drupal\billwerk_subscriptions_entities\BillwerkEntitiesHelper;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Subscriber for whenever the user should be refreshed from the subscription.
 *
 * Implements the specific actions to take on the user profile in such a case,
 * like updating the user data with values from the Billwerk Customer and
 * the user roles with the roles associated with the Billwerk Contract
 * subscriptions.
 */
class SubscriberRefreshUserSubscriber implements EventSubscriberInterface {

  /**
   * The settings config.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected ImmutableConfig $config;

  /**
   * Constructs a SubscriberRefreshUserSubscriber object.
   */
  public function __construct(
    protected readonly LogHelper $logHelper,
    ConfigFactoryInterface $configFactory,
    protected readonly Environment $environment,
    protected readonly BillwerkEntitiesHelper $billwerkEntitiesHelper,
    protected readonly BillwerkRolesManager $billwerkRolesManager,
  ) {
    $this->config = $configFactory->get('billwerk_subscriptions_handler_default.settings');
  }

  /**
   * Handles a subscriber refresh user event.
   *
   * @param \Drupal\billwerk_subscriptions\Event\SubscriberRefreshUserEvent $event
   *   The subscriber refresh user event.
   *
   * @throws \Drupal\billwerk_subscriptions\Exception\SubscriberException
   *   Thrown when the user could not be loaded from the subscriber.
   */
  public function onSubscriberRefreshUser(SubscriberRefreshUserEvent $event): void {
    $subscriber = $event->getSubscriber();
    $user = $subscriber->getUser();
    if (empty($user) || empty($user->id())) {
      throw new SubscriberException('User could not be loaded from the subscriber');
    }

    $userChanged = $this->updateUserData($event);
    $userChanged = $this->updateUserRoles($event) || $userChanged;
    $userChanged = $this->updateUserStatus($event) || $userChanged;
    if ($userChanged) {
      // Save the user if it changed.
      $user->save();
    }
  }

  /**
   * Updates the user data.
   *
   * @param \Drupal\billwerk_subscriptions\Event\SubscriberRefreshUserEvent $event
   *   The subscriber refresh user event.
   *
   * @return bool
   *   TRUE if the user data was updated, FALSE otherwise.
   */
  protected function updateUserData(SubscriberRefreshUserEvent $event): bool {
    $subscriber = $event->getSubscriber();
    $user = $subscriber->getUser();
    $subscriberBillwerkContract = $subscriber->getBillwerkContract();
    $userChanged = FALSE;

    // Update external ID, mail and status:
    if ($this->config->get('fetch_overwrite_status') && $user->hasField('status')) {
      if ($user->isActive()) {
        if ($subscriberBillwerkContract->getBillwerkCustomer()->getIsLocked()) {
          // The Drupal account is active, but the Billwerk Customer is locked!
          $this->logHelper->info(
          'User #@uid was active in Drupal, but his Billwerk Customer #@billwerkCustomerId is locked. Setting the Drupal user inactive for this reason!',
          [
            '@uid' => $user->id(),
            '@billwerkCustomerId' => $subscriberBillwerkContract->getBillwerkCustomer()->getId(),
          ],
          [],
          __CLASS__ . __FUNCTION__
          );
          // Disable the Drupal user:
          $user->set('status', FALSE);
          $userChanged = TRUE;
        }

        if ($subscriberBillwerkContract->getBillwerkCustomer()->getIsHidden()) {
          // The Drupal account is active, but the Billwerk Customer is hidden!
          $this->logHelper->info(
          'User #@uid was active in Drupal, but his Billwerk Customer #@billwerkCustomerId is hidden. Setting the Drupal user inactive for this reason!',
          [
            '@uid' => $user->id(),
            '@billwerkCustomerId' => $subscriberBillwerkContract->getBillwerkCustomer()->getId(),
          ],
          [],
          __CLASS__ . __FUNCTION__
          );
          // Disable the Drupal user:
          $user->set('status', FALSE);
          $userChanged = TRUE;
        }

      }
      else {
        if (!$subscriberBillwerkContract->getBillwerkCustomer()->getIsLocked() && !$subscriberBillwerkContract->getBillwerkCustomer()->getIsHidden()) {
          $this->logHelper->warning(
          'User #@uid is blocked in Drupal, but his Billwerk Customer #@billwerkCustomerId is neither locked or hidden. We do not automatically (re-)activate Drupal accounts as we can not tell why the user is blocked and unblocking would be risky. Please check the user details and subscription manually.',
          [
            '@uid' => $user->id(),
            '@billwerkCustomerId' => $subscriberBillwerkContract->getBillwerkCustomer()->getId(),
          ],
          [],
          __CLASS__ . __FUNCTION__
          );
        }
      }
    }

    if ($this->config->get('fetch_overwrite_mail') && $user->hasField('mail')) {
      $billwerkMailAddress = $subscriberBillwerkContract->getBillwerkCustomer()->getEmailAddress();
      $drupalMailAddress = $user->getEmail();
      if (!empty($billwerkMailAddress) && $drupalMailAddress !== $billwerkMailAddress) {
        $this->logHelper->info(
        'User #@uid email address was updated to "@billwerkMailAddress" from "@drupalMailAddress" because Email Address overwrite from Billwerk is enabled.',
        [
          '@uid' => $user->id(),
          '@billwerkCustomerId' => $subscriberBillwerkContract->getBillwerkCustomer()->getId(),
          '@drupalMailAddress' => $drupalMailAddress,
          '@billwerkMailAddress' => $billwerkMailAddress,
        ],
        [],
        __CLASS__ . __FUNCTION__
        );
        $user->set('mail', $billwerkMailAddress);
        $userChanged = TRUE;
      }
    }

    return $userChanged;
  }

  /**
   * Updates the user roles.
   *
   * @param \Drupal\billwerk_subscriptions\Event\SubscriberRefreshUserEvent $event
   *   The subscriber refresh user event.
   *
   * @return bool
   *   TRUE if the user roles were updated, FALSE otherwise.
   *
   * @throws \Drupal\billwerk_subscriptions\Exception\SubscriberException
   *   Thrown when the user could not be loaded from the subscriber.
   */
  protected function updateUserRoles(SubscriberRefreshUserEvent $event): bool {
    $subscriber = $event->getSubscriber();
    $user = $subscriber->getUser();
    $currentUserRoleIds = $user->getRoles();
    if (empty($user) || empty($user->id())) {
      throw new SubscriberException('User could not be loaded from the subscriber');
    }
    $subscriberBillwerkContract = $subscriber->getBillwerkContract();
    $userChanged = FALSE;
    /** @var \Drupal\user\Entity\Role[] $assignRoles */
    $assignRoles = [];

    $subscriberBillwerkContractSubscription = $subscriberBillwerkContract->getBillwerkContractSubscription();

    // Get the ACTIVE user subscription and retrieve their role from
    // billwerk_subscriptions_entities submodule:
    $subscriptionPhaseType = $subscriberBillwerkContractSubscription->getPhaseType();
    $subscriptionPlanVariantId = $subscriberBillwerkContractSubscription->getPlanVariantId();
    if (in_array($subscriptionPhaseType,
    [
      BillwerkContractSubscription::PHASE_TYPE_NORMAL,
      BillwerkContractSubscription::PHASE_TYPE_TRIAL,
    ]
     )) {
      // Active plan variant subscription!
      $planVariantEntity = $this->billwerkEntitiesHelper->getBillwerkPlanVariantByPlanVariantId($subscriptionPlanVariantId, $this->environment, TRUE, FALSE);
      if (!empty($planVariantEntity)) {
        $assignRoles[] = $planVariantEntity->getRoleId();
      }
      else {
        $this->logHelper->warning("Could not load the Plan Variant entity with Billwerk ID: #{$subscriptionPlanVariantId}. Typically all relevant Plan Variants in a contract assigned to a user should exist as Drupal entity.");
      }

      // Get the ACTIVE user subscriptions components and retrieve their roles
      // from billwerk_subscriptions_entities:
      $subscriberBillwerkContractComponentSubscriptions = $subscriberBillwerkContractSubscription->getComponentSubscriptions();
      foreach ($subscriberBillwerkContractComponentSubscriptions as $componentSubscription) {
        /** @var \Drupal\billwerk_subscriptions\DataObject\BillwerkContractComponentSubscription $componentSubscription */
        // We currently don't use the quantity in our example.
        // $componentQuantity = $componentSubscription->getQuantity();
        $billwerkComponentId = $componentSubscription->getComponentId();
        $componentEntity = $this->billwerkEntitiesHelper->getBillwerkComponentByComponentId($billwerkComponentId, $this->environment, TRUE, FALSE);
        if (!empty($componentEntity)) {
          $assignRoles[] = $componentEntity->getRoleId();
        }
        else {
          $this->logHelper->warning("Could not load the Component entity with Billwerk ID: #{$billwerkComponentId}. Typically all relevant Components in a contract assigned to a user should exist as Drupal entity.");
        }
      }
    }
    elseif (in_array(
    $subscriptionPhaseType,
    [
      BillwerkContractSubscription::PHASE_TYPE_INACTIVE,
    ]
     )) {
      // Inactive plan variant subscription!
      // We do nothing here.
    }
    else {
      throw new SubscriberException("Unhandled subscription phase type: {$subscriptionPhaseType}. All phase types should be handled to ensure correct functionality!");
    }

    // Compare the existing roles (that are handled by billwerk (Setting!)) to
    // the calculated roles. Remove all roles (that are handled by billwerk
    // (Setting!)) and set the new ones.
    $billwerkRoleIds = $this->billwerkRolesManager->getBillwerkRoles();
    $currentUserBillwerkRoleIds = array_intersect($currentUserRoleIds, $billwerkRoleIds);

    $removeRoles = array_diff($currentUserBillwerkRoleIds, $assignRoles);
    $addRoles = array_diff($assignRoles, $currentUserBillwerkRoleIds);
    foreach ($removeRoles as $removeRole) {
      $user->removeRole($removeRole);
      $userChanged = TRUE;
    }
    foreach ($addRoles as $addRole) {
      $user->addRole($addRole);
      $userChanged = TRUE;
    }
    return $userChanged;
  }

  /**
   * Updates the user status.
   *
   * @param \Drupal\billwerk_subscriptions\Event\SubscriberRefreshUserEvent $event
   *   The subscriber refresh user event.
   *
   * @return bool
   *   TRUE if the user status was updated, FALSE otherwise.
   */
  public function updateUserStatus(SubscriberRefreshUserEvent $event): bool {
    $subscriber = $event->getSubscriber();
    $user = $subscriber->getUser();
    $subscriberBillwerkContract = $subscriber->getBillwerkContract();
    $subscriberBillwerkCustomer = $subscriberBillwerkContract->getBillwerkCustomer();

    if (!$user->isBlocked() && ($subscriberBillwerkCustomer->getIsLocked())) {
      // Block the user, if it is locked at Billwerk:
      $user->block();
      $this->logHelper->info(
      'Blocked User #@uid because the Customer is locked at Billwerk.',
      [
        '@uid' => $subscriber->getUser()->id(),
      ],
      NULL, __CLASS__ . __FUNCTION__);
      return TRUE;
    }
    elseif (!$user->isBlocked() && ($subscriberBillwerkCustomer->isDeleted())) {
      // Block the user, if it is locked at Billwerk:
      $user->block();
      $this->logHelper->info(
      'Blocked User #@uid because the Customer is deleted at Billwerk. Former Billwerk Contract ID: @billwerk_contract_id',
      [
        '@uid' => $subscriber->getUser()->id(),
        '@billwerk_contract_id' => $subscriberBillwerkContract->getId(),
      ],
      NULL, __CLASS__ . __FUNCTION__);
      return TRUE;
    }
    elseif ($user->isBlocked() && !$subscriberBillwerkCustomer->getIsLocked()) {
      // Unblock the user if it is unblocked at Billwerk:
      // @codingStandardsIgnoreStart
      // We currently do NOT automatically unblock user accounts because that may be risky.
      // This should be done manually to ensure no user is unblocked that should not be.
      // $user->activate();
      // $this->logHelper->info(
      //     'Unblocked User #@uid because the Customer is unlocked at Billwerk.',
      //     [
      //         '@uid' => $subscriber->getUser()->id(),
      //     ],
      //     NULL, __CLASS__ . __FUNCTION__);
      // return TRUE;.
      // @codingStandardsIgnoreEnd
    }

    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    return [
      SubscriberRefreshUserEvent::class => ['onSubscriberRefreshUser'],
    ];
  }

}

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

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