View source  
  <?php
namespace Drupal\acquia_contenthub\Client;
use Acquia\ContentHubClient\ContentHub;
use Drupal\acquia_contenthub\Middleware\MiddlewareCollector;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Uuid\Uuid;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ServerException;
use Symfony\Component\HttpFoundation\Request;
class ClientManager implements ClientManagerInterface {
  use StringTranslationTrait;
  
  protected $loggerFactory;
  
  protected $configFactory;
  
  protected $client;
  
  protected $languageManager;
  
  protected $config;
  
  protected $clientUserAgent;
  
  protected $collector;
  
  public function __construct(LoggerChannelFactoryInterface $logger_factory, ConfigFactoryInterface $config_factory, LanguageManagerInterface $language_manager, MiddlewareCollector $collector, ModuleExtensionList $module_extension_list) {
    $this->loggerFactory = $logger_factory;
    
    $module_info = array_merge($module_extension_list
      ->getAllInstalledInfo()['acquia_contenthub'], [
      'version' => '0.0.0',
      'core' => '0.0.0',
    ]);
    $this->clientUserAgent = 'AcquiaContentHub/' . $module_info['core'] . '-' . $module_info['version'];
    $this->configFactory = $config_factory;
    $this->languageManager = $language_manager;
    $this->collector = $collector;
    
    $this->config = $this->configFactory
      ->get('acquia_contenthub.admin_settings');
    
    $this
      ->setConnection();
  }
  
  protected function setConnection(array $config = []) {
    $this->client =& drupal_static(__METHOD__);
    if (NULL === $this->client) {
      $hostname = $this->config
        ->get('hostname');
      
      $config = array_merge([
        'base_url' => $hostname,
        'client-user-agent' => $this->clientUserAgent,
        'adapterConfig' => [
          'schemaId' => 'Drupal8',
          'defaultLanguageId' => $this->languageManager
            ->getDefaultLanguage()
            ->getId(),
        ],
      ], $config);
      
      $api = $this->config
        ->get('api_key');
      $secret = $this->config
        ->get('secret_key');
      $client_name = $this->config
        ->get('client_name');
      $origin = $this->config
        ->get('origin');
      
      if (!Uuid::isValid($origin) || empty($client_name) || empty($hostname) || empty($api) || empty($secret)) {
        return FALSE;
      }
      $this->client = new ContentHub($origin, $this->collector
        ->getMiddlewares(), $config);
    }
    return $this;
  }
  
  public function getConnection(array $config = []) {
    return $this->client;
  }
  
  public function resetConnection(array $variables, array $config = []) {
    
    $api = $variables['api'] ?? '';
    $secret = $variables['secret'] ?? '';
    foreach ($this->collector
      ->getMiddlewares() as $middleware) {
      $middleware
        ->setApiKey($api);
      $middleware
        ->setSecretKey($secret);
    }
    
    $hostname = $variables['hostname'] ?? $this->config
      ->get('hostname');
    $origin = $variables['origin'] ?? $this->config
      ->get('origin');
    
    $config = array_merge([
      'base_url' => $hostname,
      'client-user-agent' => $this->clientUserAgent,
      'adapterConfig' => [
        'schemaId' => 'Drupal8',
        'defaultLanguageId' => $this->languageManager
          ->getDefaultLanguage()
          ->getId(),
      ],
    ], $config);
    $this->client = new ContentHub($origin, $this->collector
      ->getMiddlewares(), $config);
  }
  
  public function isConnected() {
    
    if (empty($this
      ->getConnection())) {
      return FALSE;
    }
    
    return TRUE;
  }
  
  public function isClientNameAvailable($client_name) {
    if ($site = $this
      ->createRequest('getClientByName', [
      $client_name,
    ])) {
      if (isset($site['uuid']) && Uuid::isValid($site['uuid'])) {
        return FALSE;
      }
    }
    return TRUE;
  }
  
  public function getRequestSignature(Request $request, $secret_key = '') {
    
    $headers = array_map('current', $request->headers
      ->all());
    $http_verb = $request
      ->getMethod();
    
    $path = $request
      ->getRequestUri();
    $body = $request
      ->getContent();
    
    $content_type = isset($headers['content-type']) ? $headers['content-type'] : '';
    $date = isset($headers['date']) ? $headers['date'] : '';
    $message_array = [
      $http_verb,
      md5($body),
      $content_type,
      $date,
      '',
      $path,
    ];
    $message = implode("\n", $message_array);
    $s = hash_hmac('sha256', $message, $secret_key, TRUE);
    $signature = base64_encode($s);
    return $signature;
  }
  
  public function createRequest($request, array $args = [], array $exception_messages = []) {
    try {
      
      if (empty($this
        ->getConnection())) {
        $error = $this
          ->t('This client is NOT registered to Content Hub. Please register first');
        throw new \Exception($error);
      }
      
      switch ($request) {
        
        case 'ping':
        case 'definition':
          return $this
            ->getConnection()
            ->{$request}();
        
        case 'getSettings':
        case 'purge':
        case 'restore':
        case 'reindex':
        case 'mapping':
        case 'regenerateSharedSecret':
          return $this->client
            ->{$request}();
        
        case 'register':
        case 'getClientByName':
        case 'createEntity':
        case 'createEntities':
        case 'putEntities':
        case 'readEntity':
        case 'readEntities':
        case 'updateEntities':
        case 'deleteEntity':
        case 'listEntities':
        case 'addWebhook':
        case 'deleteWebhook':
        
        case 'searchEntity':
          if (!isset($args[0])) {
            $error = $this
              ->t('Request %request requires %num argument.', [
              '%request' => $request,
              '%num' => 1,
            ]);
            throw new \Exception($error);
          }
          return $this->client
            ->{$request}($args[0]);
        
        case 'logs':
        case 'updateEntity':
          if (!isset($args[0]) || !isset($args[1])) {
            $error = $this
              ->t('Request %request requires %num arguments.', [
              '%request' => $request,
              '%num' => 2,
            ]);
            throw new \Exception($error);
          }
          return $this->client
            ->{$request}($args[0], $args[1]);
      }
    } catch (ServerException $ex) {
      $msg = $this
        ->getExceptionMessage($request, $args, $ex, $exception_messages);
    } catch (ConnectException $ex) {
      $msg = $this
        ->getExceptionMessage($request, $args, $ex, $exception_messages);
    } catch (ClientException $ex) {
      $response = json_decode($ex
        ->getResponse()
        ->getBody(), TRUE);
      $msg = $this
        ->getExceptionMessage($request, $args, $ex, $exception_messages, $response);
    } catch (RequestException $ex) {
      $msg = $this
        ->getExceptionMessage($request, $args, $ex, $exception_messages);
    } catch (\Exception $ex) {
      $msg = $this
        ->getExceptionMessage($request, $args, $ex, $exception_messages);
    }
    
    if (isset($msg)) {
      if ($msg !== FALSE) {
        $this->loggerFactory
          ->get('acquia_contenthub')
          ->error($msg);
        
      }
      else {
        
        return TRUE;
      }
    }
    return FALSE;
  }
  
  protected function getExceptionMessage($request, array $args, $ex, array $exception_messages = [], $response = NULL) {
    
    $exception = implode('', array_slice(explode('\\', get_class($ex)), -1));
    switch ($exception) {
      case 'ServerException':
        if (isset($exception_messages['ServerException'])) {
          $msg = $exception_messages['ServerException'];
        }
        else {
          $msg = new FormattableMarkup('Could not reach the Content Hub. Please verify your hostname and Credentials. [Error message: @msg]', [
            '@msg' => $ex
              ->getMessage(),
          ]);
        }
        break;
      case 'ConnectException':
        if (isset($exception_messages['ConnectException'])) {
          $msg = $exception_messages['ConnectException'];
        }
        else {
          $msg = new FormattableMarkup('Could not reach the Content Hub. Please verify your hostname URL. [Error message: @msg]', [
            '@msg' => $ex
              ->getMessage(),
          ]);
        }
        break;
      case 'ClientException':
      case 'BadResponseException':
      case 'ServerErrorResponseException':
        if (isset($exception_messages[$exception])) {
          $msg = $exception_messages[$exception];
        }
        else {
          if (isset($response) && isset($response['error'])) {
            
            $error = $response['error'];
            switch ($request) {
              
              case 'register':
                $client_name = $args[0];
                $msg = new FormattableMarkup('Error registering client with name="@name" (Error Code = @error_code: @error_message)', [
                  '@error_code' => $error['code'],
                  '@name' => $client_name,
                  '@error_message' => $error['message'],
                ]);
                break;
              case 'getClientByName':
                
                $code = $ex
                  ->getResponse()
                  ->getStatusCode();
                if ($code == 404) {
                  
                  return FALSE;
                }
                else {
                  $msg = new FormattableMarkup('Error trying to connect to the Content Hub" (Error Code = @error_code: @error_message)', [
                    '@error_code' => $error['code'],
                    '@error_message' => $error['message'],
                  ]);
                }
                break;
              case 'addWebhook':
                $webhook_url = $args[0];
                $msg = new FormattableMarkup('There was a problem trying to register Webhook URL = %URL. Please try again. (Error Code = @error_code: @error_message)', [
                  '%URL' => $webhook_url,
                  '@error_code' => $error['code'],
                  '@error_message' => $error['message'],
                ]);
                break;
              case 'deleteWebhook':
                
                $webhook_url = isset($args[1]) ? $args[1] : $args[0];
                $msg = new FormattableMarkup('There was a problem trying to <b>unregister</b> Webhook URL = %URL. Please try again. (Error Code = @error_code: @error_message)', [
                  '%URL' => $webhook_url,
                  '@error_code' => $error['code'],
                  '@error_message' => $error['message'],
                ]);
                break;
              case 'purge':
                $msg = new FormattableMarkup('Error purging entities from the Content Hub [Error Code = @error_code: @error_message]', [
                  '@error_code' => $error['code'],
                  '@error_message' => $error['message'],
                ]);
                break;
              case 'readEntity':
                $uuid = $args[0];
                $msg = new FormattableMarkup('Entity with UUID="@uuid" was referenced by another entity, but could not be found in Content Hub. To resolve this warning, enable publishing of that entity type on the publishing site and re-export the entity. (Error Code = @error_code: @error_message)', [
                  '@error_code' => $error['code'],
                  '@uuid' => $uuid,
                  '@error_message' => $error['message'],
                ]);
                break;
              case 'createEntity':
                $msg = new FormattableMarkup('Error trying to create an entity in Content Hub (Error Code = @error_code: @error_message)', [
                  '@error_code' => $error['code'],
                  '@error_message' => $error['message'],
                ]);
                break;
              case 'createEntities':
                $msg = new FormattableMarkup('Error trying to create entities in Content Hub (Error Code = @error_code: @error_message)', [
                  '@error_code' => $error['code'],
                  '@error_message' => $error['message'],
                ]);
                break;
              case 'updateEntity':
                $uuid = $args[1];
                $msg = new FormattableMarkup('Error trying to update an entity with UUID="@uuid" in Content Hub (Error Code = @error_code: @error_message)', [
                  '@uuid' => $uuid,
                  '@error_code' => $error['code'],
                  '@error_message' => $error['message'],
                ]);
                break;
              case 'updateEntities':
                $msg = new FormattableMarkup('Error trying to update some entities in Content Hub (Error Code = @error_code: @error_message)', [
                  '@error_code' => $error['code'],
                  '@error_message' => $error['message'],
                ]);
                break;
              case 'deleteEntity':
                $uuid = $args[0];
                $msg = new FormattableMarkup('Error trying to delete entity with UUID="@uuid" in Content Hub (Error Code = @error_code: @error_message)', [
                  '@uuid' => $uuid,
                  '@error_code' => $error['code'],
                  '@error_message' => $error['message'],
                ]);
                break;
              case 'searchEntity':
                $msg = new FormattableMarkup('Error trying to make a search query to Content Hub. Are your credentials inserted correctly? (Error Code = @error_code: @error_message)', [
                  '@error_code' => $error['code'],
                  '@error_message' => $error['message'],
                ]);
                break;
              default:
                $msg = new FormattableMarkup('Error trying to connect to the Content Hub" (Error Code = @error_code: @error_message)', [
                  '@error_code' => $error['code'],
                  '@error_message' => $error['message'],
                ]);
            }
          }
          else {
            $msg = new FormattableMarkup('Error trying to connect to the Content Hub (Error Message = @error_message)', [
              '@error_message' => $ex
                ->getMessage(),
            ]);
          }
        }
        break;
      case 'RequestException':
        if (isset($exception_messages['RequestException'])) {
          $msg = $exception_messages['RequestException'];
        }
        else {
          switch ($request) {
            
            case 'register':
              $client_name = $args[0];
              $msg = new FormattableMarkup('Could not get authorization from Content Hub to register client @name. Are your credentials inserted correctly? (Error message = @error_message)', [
                '@name' => $client_name,
                '@error_message' => $ex
                  ->getMessage(),
              ]);
              break;
            case 'createEntity':
              $msg = new FormattableMarkup('Error trying to create an entity in Content Hub (Error Message: @error_message)', [
                '@error_message' => $ex
                  ->getMessage(),
              ]);
              break;
            case 'createEntities':
              $msg = new FormattableMarkup('Error trying to create entities in Content Hub (Error Message = @error_message)', [
                '@error_message' => $ex
                  ->getMessage(),
              ]);
              break;
            case 'updateEntity':
              $uuid = $args[1];
              $msg = new FormattableMarkup('Error trying to update entity with UUID="@uuid" in Content Hub (Error Message = @error_message)', [
                '@uuid' => $uuid,
                '@error_message' => $ex
                  ->getMessage(),
              ]);
              break;
            case 'updateEntities':
              $msg = new FormattableMarkup('Error trying to update some entities in Content Hub (Error Message = @error_message)', [
                '@error_message' => $ex
                  ->getMessage(),
              ]);
              break;
            case 'deleteEntity':
              $uuid = $args[0];
              $msg = new FormattableMarkup('Error trying to delete entity with UUID="@uuid" in Content Hub (Error Message = @error_message)', [
                '@uuid' => $uuid,
                '@error_message' => $ex
                  ->getMessage(),
              ]);
              break;
            case 'searchEntity':
              $msg = new FormattableMarkup('Error trying to make a search query to Content Hub. Are your credentials inserted correctly? (Error Message = @error_message)', [
                '@error_message' => $ex
                  ->getMessage(),
              ]);
              break;
            default:
              $msg = new FormattableMarkup('Error trying to connect to the Content Hub. Are your credentials inserted correctly? (Error Message = @error_message)', [
                '@error_message' => $ex
                  ->getMessage(),
              ]);
          }
        }
        break;
      case 'Exception':
      default:
        if (isset($exception_messages['Exception'])) {
          $msg = $exception_messages['Exception'];
        }
        else {
          $msg = new FormattableMarkup('Error trying to connect to the Content Hub (Error Message = @error_message)', [
            '@error_message' => $ex
              ->getMessage(),
          ]);
        }
        break;
    }
    return $msg;
  }
}