commercetools-8.x-1.2-alpha1/src/EventSubscriber/CommercetoolsExceptionSubscriber.php

src/EventSubscriber/CommercetoolsExceptionSubscriber.php
<?php

namespace Drupal\commercetools\EventSubscriber;

use Commercetools\Exception\ApiClientException;
use Commercetools\Exception\UnauthorizedException;
use Drupal\commercetools\CommercetoolsService;
use Drupal\commercetools\Exception\CommercetoolsGraphqlErrorException;
use Drupal\commercetools\Exception\CommercetoolsMissingPermissionException;
use Drupal\commercetools\Exception\CommercetoolsOperationFailedException;
use Drupal\Core\Link;
use Drupal\Core\Logger\LoggerChannelTrait;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\Core\Utility\Error;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Exception\RequestException;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Subscribes to kernel exceptions events and generates a Span Event.
 */
class CommercetoolsExceptionSubscriber implements EventSubscriberInterface {
  use StringTranslationTrait;
  use LoggerChannelTrait;

  const REQUEST_FORMAT_HTML = 'html';

  /**
   * Constructs the CommercetoolsExceptionEventSubscriber object.
   *
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   *   A Symfony container.
   */
  public function __construct(
    protected ContainerInterface $container,
  ) {
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    return [
        // Set weight to 60 to execute before the ExceptionLoggingSubscriber
        // that logs the not found pages.
      KernelEvents::EXCEPTION => ['onException', 60],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function onException(ExceptionEvent $event) {
    // Act only on Commercetools related exceptions.
    $eClass = get_class($event->getThrowable());
    if (
      !str_starts_with($eClass, 'Drupal\commercetools')
      && !str_starts_with($eClass, 'Commercetools\\')
    ) {
      return;
    }

    $e = $event->getThrowable();

    if ($e instanceof CommercetoolsOperationFailedException) {
      $this->logException($e);
    }

    $configFactory = $this->container->get('config.factory');
    $errorLevel = $configFactory->get('system.logging')->get('error_level');

    // For the expected basic errors on the module side - displaying a more
    // detailed errors with explanations on how to fix them.
    $ctApi = $this->container->get('commercetools.api');
    $displayConnectionError = $configFactory->get(CommercetoolsService::CONFIGURATION_NAME)->get(CommercetoolsService::CONFIG_DISPLAY_CONNECTION_ERRORS);
    if ($displayConnectionError) {
      $accessConfigured = $ctApi->isAccessConfigured();

      $settingsLink = Link::fromTextAndUrl(t('commercetools settings page'), Url::fromRoute('commercetools.settings'))->toString();

      $displayMessageLevel = MessengerInterface::TYPE_ERROR;
      if (!$accessConfigured) {
        $displayMessageLevel = MessengerInterface::TYPE_WARNING;
        $displayMessage = $this->t('You have not configured the commercetools credentials. Open the @link and set the credentials.', [
          '@link' => $settingsLink,
        ]) . ' ' . $this->addDemoModuleLink();

      }
      elseif (
        $e instanceof CommercetoolsOperationFailedException
        || $e instanceof CommercetoolsGraphqlErrorException
      ) {
        // The text coming from variables is predictable, we have translate it.
        // phpcs:ignore
        $displayMessage = $this->t($e->getMessage());
        if ($e instanceof CommercetoolsGraphqlErrorException) {
          $displayMessage = 'commercetools GraphQL error: ' . $displayMessage;
        }
        if (
          $errorLevel !== ERROR_REPORTING_HIDE
          && $ePrevious = $e->getPrevious()
        ) {
          if ($ePrevious instanceof UnauthorizedException) {
            $displayMessage = $this->t('Commercetools API responds with the access denied error using the configured credentials. Check the credentials and the API host on the @link page and check the logs for the more detailed information.', [
              '@link' => $settingsLink,
            ]) . ' ' . $this->addDemoModuleLink();
          }
          else {
            $displayMessage .= "\n\nParent error: " . $ePrevious->getMessage();
            $displayMessage = rtrim($displayMessage, '. ') . '. ';

            if ($ePrevious instanceof BadResponseException || $ePrevious instanceof RequestException) {
              $ePreviousResponse = $ePrevious->getResponse();
              if ($ePreviousResponse) {
                $errorMessages = $this->parseGraphqlErrorResponse($ePreviousResponse->getBody()->__toString());
                $displayMessage .= " Response error: " . implode("\n", $errorMessages) . "\n\n";
              }
            }
          }
        }
      }
      elseif ($e instanceof CommercetoolsMissingPermissionException) {
        $displayMessage = $this->t('The operation failed because of the missing permissions on the commercetools account using the configured credentials. Check the permission configuration on the commercetools Merchant Center.', [
          '@link' => $settingsLink,
        ]);
      }
      else {
        // Do nothing to display the original exception.
      }
      if (
        isset($displayMessage)
        && $event->getRequest()->getRequestFormat() == self::REQUEST_FORMAT_HTML
      ) {
        if ($this->container->has('messenger')) {
          $this->container->get('messenger')->addMessage(nl2br($displayMessage), $displayMessageLevel);
          // Fall back to the Drupal default access denied page to display
          // the message.
          $e = new AccessDeniedHttpException($displayMessage, $e);
          $event->setThrowable($e);
          return;
        }
      }
      else {
        $ePrevious = $e->getPrevious();
        if ($ePrevious) {
          $parentMessage = $ePrevious->getMessage();
          $parentClass = get_class($ePrevious);
          $e = new CommercetoolsOperationFailedException("$displayMessage Parent exception ($parentClass): $parentMessage", 0, $e);
          $event->setThrowable($e);
        }
      }
    }
  }

  /**
   * Adds the demo module information.
   */
  private function addDemoModuleLink() {
    if ($this->container->has('module_handler')) {
      $moduleHandler = $this->container->get('module_handler');
      if ($moduleHandler->moduleExists('commercetools_demo')) {
        return $this->t('Also, you can configure the demo credentials on the @link page.', [
          '@link' => Link::fromTextAndUrl('commercetools Demo configuration', Url::fromRoute('commercetools_demo.settings'))->toString(),
        ]);
      }
      else {
        return $this->t('Also, you can <a href=@url>install the "commercetools Demo" module</a> to test the functionality with pre-configured commercetools accounts.', [
          '@url' => Url::fromRoute('system.modules_list', options: ['fragment' => 'module-commercetools-demo'])->toString(),
        ]);

      }
    }
  }

  /**
   * Parses the GraphQL error response and returns an array of error texts.
   *
   * @param string $response
   *   The GraphQL response text.
   *
   * @return array|null
   *   An array with error messages, or null if no messages found.
   */
  private function parseGraphqlErrorResponse(string $response): ?array {
    $data = json_decode($response, TRUE);
    if (isset($data['errors'])) {
      foreach ($data['errors'] as $error) {
        if (isset($error['message'])) {
          $messages[] = $error['message'];
        }
      }
    }
    return $messages ?? NULL;
  }

  /**
   * Logs a Commercetools API exception.
   */
  protected function logException(\Throwable $e): void {
    $error = Error::decodeException($e);
    $previous = $e->getPrevious();

    if ($previous instanceof ApiClientException) {
      $error['@message'] .= '; ' . $previous->getMessage();
    }

    $this->getLogger('commercetools_api')
      ->error(Error::DEFAULT_ERROR_MESSAGE, $error);
  }

}

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

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