bynder-4.0.0-beta1/src/BynderApi.php

src/BynderApi.php
<?php

namespace Drupal\bynder;

use Bynder\Api\BynderClient;
use Bynder\Api\Impl\PermanentTokens\Configuration;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Url;
use League\OAuth2\Client\Token\AccessToken;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

/**
 * Bynder API service.
 *
 * @method array getBrands()
 * @method array getMediaList(array $query)
 * @method array|null getMediaInfo(string $media_id, int $versions)
 * @method array getMetaproperties(array $query)
 * @method array uploadFileAsync(array $data)
 * @method array getDerivatives()
 *
 * @package Drupal\bynder
 */
class BynderApi implements BynderApiInterface {

  /**
   * The Bynder integration ID.
   */
  const BYNDER_INTEGRATION_ID = 'a7129512-c6e3-47a3-be40-9a66503e82ed';

  /**
   * Cache ID used to store the tags information.
   */
  const CID_TAGS = 'bynder_tags';

  /**
   * Cache ID used to store the metaproperties information.
   */
  const CID_METAPROPERTIES = 'bynder_metaproperties';

  /**
   * Cache ID used to store the derivatives information.
   */
  const CID_DERIVATIVES = 'bynder_derivatives';

  /**
   * List of API calls that should be cache with their cache keys as values.
   */
  const CACHED_CALLS = [
    'getMetaproperties' => self::CID_METAPROPERTIES,
    'getDerivatives' => self::CID_DERIVATIVES,
  ];

  /**
   * List of getTags queries that are automatically updated in crons.
   */
  const AUTO_UPDATED_TAGS_QUERIES = [
    NULL,
    [
      'limit' => 500,
      'orderBy' => 'mediaCount desc',
      'minCount' => 1,
    ],
  ];

  /**
   * Bynder Api instance.
   *
   * @var \Bynder\Api\BynderClient
   */
  protected $bynderApi;

  /**
   * Bynder configuration.
   *
   * Contains array with keys consumer_key, consumer_secret, token, token_secret
   * and account_domain.
   *
   * @var array
   */
  protected $bynderConfig;

  /**
   * The configuration factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The logger factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactory
   */
  protected $loggerFactory;

  /**
   * The active session.
   *
   * @var \Symfony\Component\HttpFoundation\Session\SessionInterface
   */
  protected $session;

  /**
   * The state service.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * The cache service.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cache;

  /**
   * The time service.
   *
   * @var \Drupal\Component\Datetime\TimeInterface $time
   */
  protected $time;

  /**
   * The configuration object.
   *
   * @var \Bynder\Api\Impl\PermanentTokens\Configuration|\Bynder\Api\Impl\OAuth2\Configuration
   */
  protected $bynderConfiguration;

  /**
   * BynderApi constructor.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   Config factory.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   Logger factory.
   * @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
   *   The session service.
   * @param \Drupal\Core\State\StateInterface $state
   *   The state service.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
   *   The cache service.
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The time service.
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    LoggerChannelFactoryInterface $logger_factory,
    SessionInterface $session,
    StateInterface $state,
    CacheBackendInterface $cache,
    TimeInterface $time
  ) {
    $this->configFactory = $config_factory;
    $this->loggerFactory = $logger_factory;
    $this->session = $session;
    $this->state = $state;
    $this->cache = $cache;
    $this->time = $time;
  }

  /**
   * {@inheritdoc}
   */
  public function initiateOAuthTokenRetrieval() {
    $bynder_settings = $this->configFactory->get('bynder.settings');

    if (!$bynder_settings->get('client_id') || !$bynder_settings->get('client_secret')) {
      throw new \Exception('Client ID or secret configuration missing');
    }

    $query = [
      'client_id' => $bynder_settings->get('client_id'),
      'redirect_uri' => $this->getCallback(),
      'scope' => 'offline asset:read asset:write asset.usage:read asset.usage:write current.user:read current.profile:read',
      'response_type' => 'code',
      'state' => 'state',
    ];

    return Url::fromUri('https://' . $bynder_settings->get('account_domain') .  '/v6/authentication/oauth2/auth',
      array(
        'query' => $query,
        'auth' => null,
        'allow_redirects' => false
      )
    );
  }

  /**
   * {@inheritdoc}
   */
  public function hasAccessToken() {
    $session_data = $this->session->get('bynder', []);

    // Required tokens need to be stored in the session.
    if (empty($session_data['access_token']) || !$session_data['access_token'] instanceof AccessToken) {
      return FALSE;
    }

    // In case of the global config change all user sessions need to expire.
    if (empty($session_data['config_hash']) || $session_data['config_hash'] != $this->state->get('bynder_config_hash')) {
      return FALSE;
    }

    // Check if the token has expired, attempt to refresh it.
    if ($session_data['access_token']->getExpires() < $this->time->getCurrentTime()) {

      try {
        // Trigger an API request.
        $this->hasUploadPermissions();
        if ($this->bynderConfiguration instanceof \Bynder\Api\Impl\OAuth2\Configuration) {

          // The updated access token might not have a refresh token, use the
          // existing one.
          $options = $this->bynderConfiguration->getToken()->jsonSerialize();
          if (empty($data['refresh_token'])) {
            $options['refresh_token'] = $session_data['access_token']->getRefreshToken();
          }

          $session_data['access_token'] = new AccessToken($options);


          $this->session->set('bynder', $session_data);
          return TRUE;
        }
        else {
          // Failed to refresh, user needs to log in again.
          $this->session->set('bynder', []);
        }
      } catch (\Exception $e) {
        // Failed to refresh, user needs to log in again.
        $this->session->set('bynder', []);
      }

      return FALSE;
    }

    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function finishOAuthTokenRetrieval($code) {
    $bynder_configuration = $this->getOauthConfiguration();
    $this->bynderApi = new BynderClient($bynder_configuration);

    $session_data = $this->session->get('bynder', []);
    $session_data['access_token'] = $this->bynderApi->getAccessToken($code);
    $session_data['config_hash'] = $this->state->get('bynder_config_hash');
    $this->session->set('bynder', $session_data);
  }

  /**
   * {@inheritdoc}
   */
  public function hasUploadPermissions() {
    $this->getAssetBankManager();
    $user = $this->bynderApi->getCurrentUser()->wait();
    if (isset($user)) {
      $profileId = $user['profileId'];
      $userProfile = $this->bynderApi->getSecurityProfile($profileId)->wait();
      foreach ($userProfile['roles'] as $role) {
        if ($role == 'MEDIAUPLOAD' || $role == 'MEDIAUPLOADFORAPPROVAL') {
          return $role;
        }
      }
    }
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function getAssetBankManager() {
    $bynder_settings = $this->configFactory->get('bynder.settings');

    $request_options = ['timeout' => $bynder_settings->get('timeout')];

    $session_data = \Drupal::service('session')->get('bynder', []);
    if ($this->bynderConfig) {
      $this->bynderConfiguration = new Configuration($this->bynderConfig['baseUrl'], $this->bynderConfig['permanent_token'], $request_options);
    }
    elseif (!empty($session_data['access_token']) && !empty($session_data['config_hash']) && $session_data['config_hash'] == $this->state->get('bynder_config_hash')) {
      // @TODO Re-evaluate where global and where user token is used.
      $this->bynderConfiguration = $this->getOauthConfiguration();
      $this->bynderConfiguration->setToken($session_data['access_token']);
    }
    else {
      $this->bynderConfiguration = new Configuration($bynder_settings->get('account_domain'), $bynder_settings->get('permanent_token'), $request_options);
    }

    $this->bynderApi = new BynderClient($this->bynderConfiguration);

    return $this->bynderApi->getAssetBankManager();
  }

  /**
   * {@inheritdoc}
   */
  public function setBynderConfiguration(array $config) {
    $this->bynderConfig = $config;
  }

  /**
   * {@inheritdoc}
   */
  public function updateCachedData() {
    $expire = $this->configFactory->get('bynder.settings')
        ->get('cache_lifetime') + $this->time->getRequestTime();
    $items = [];
    foreach (self::CACHED_CALLS as $method => $cid) {
      if ($this->configFactory->get('bynder.settings')->get('debug')) {
        $this->loggerFactory->get('bynder')->debug('Update cache: updating cached data for %method.', ['%method' => $method]);
      }

      $items[$cid] = [
        'data' => call_user_func_array([$this->getAssetBankManager(), $method], [])->wait(),
        'expire' => $expire,
      ];
    }

    foreach (static::AUTO_UPDATED_TAGS_QUERIES as $query) {
      $items[self::CID_TAGS . '_' . md5(serialize($query))] = [
        'data' => $this->getAssetBankManager()->getTags($query)->wait(),
        'expire' => $expire,
      ];
    }

    $this->cache->setMultiple($items);
    $this->state->set('bynder_cache_last_update', $this->time->getRequestTime());
  }

  /**
   * Wraps getTags() and makes sure results are cached properly.
   */
  public function getTags($query = []) {
    $bynder_configuration = $this->configFactory->get('bynder.settings');
    if ($bynder_configuration->get('debug')) {
      $this->loggerFactory->get('bynder')->debug('Method: %method is called with arguments: @args', [
        '%method' => 'getTags',
        '@args' => print_r($query, TRUE),
      ]);
    }
    try {
      if (empty($args['keyword'])) {
        $query_hash = md5(serialize($query));
        $allow_expired = FALSE;
        foreach (static::AUTO_UPDATED_TAGS_QUERIES as $candidate) {
          if (md5(serialize($candidate)) === $query_hash) {
            $allow_expired = TRUE;
            break;
          }
        }

        if ($cache_item = $this->cache->get(self::CID_TAGS . '_' . $query_hash, $allow_expired)) {
          return $cache_item->data;
        }
        else {
          $result = [];
          // Ensure all results are fetched so start with page 1
          $query['page'] = 1;
          // Set the limit to the default if not provided.
          if (!isset($query['limit'])) {
            $query['limit'] = 50;
          }
          do {
            $items = $this->getAssetBankManager()->getTags($query)->wait();
            $result = array_merge($result, $items);
            $query['page']++;
            // Continue fetching results until the response is empty, or the
            // number of items returned is less than the requested limit.
          } while (!empty($items) && (count($items) == $query['limit']));
          $this->cache->set(self::CID_TAGS . '_' . $query_hash, $result, ($this->configFactory->get('bynder.settings')->get('cache_lifetime') + $this->time->getRequestTime()));
          return $result;
        }
      }
      else {
        $result = $this->getAssetBankManager()->getTags($query)->wait();
      }

      if ($bynder_configuration->get('debug')) {
        $this->loggerFactory->get('bynder')->debug('Method: %method returns: @result', [
          '%method' => 'getTags',
          '@result' => print_r($result, TRUE),
        ]);
      }
      return $result;
    } catch (\Exception $e) {
      if ($bynder_configuration->get('debug')) {
        $this->loggerFactory->get('bynder')
          ->error('Method: %method throws error with message: @message', [
            '%method' => 'getTags',
            '@message' => $e->getMessage(),
          ]);
      }
      throw $e;
    }
  }

  public function getIntegrationId() {
    return self::BYNDER_INTEGRATION_ID;
  }

  /**
   * {@inheritdoc}
   */
  public function addAssetUsage($asset_id, $usage_url, $creation_date, $additional_info = NULL) {
    $usage_properties = [
      'integration_id' => self::BYNDER_INTEGRATION_ID,
      'asset_id' => $asset_id,
      'timestamp' => $creation_date,
      'uri' => $usage_url->setAbsolute(TRUE)->toString(),
      'additional' => $additional_info,
    ];

    return $this->getAssetBankManager()->createUsage($usage_properties)->wait();
  }

  /**
   * {@inheritdoc}
   */
  public function removeAssetUsage($asset_id, $usage_url = NULL) {
    $usageProperties = [
      'integration_id' => self::BYNDER_INTEGRATION_ID,
      'asset_id' => $asset_id,
      'uri' => $usage_url,
    ];

    return $this->getAssetBankManager()->deleteUsage($usageProperties)->wait();
  }

  /**
   * {@inheritdoc}
   */
  public function getAssetUsages($asset_id) {
    return $this->getAssetBankManager()
      ->getUsage(['asset_id' => $asset_id])
      ->wait();
  }

  /**
   * {@inheritdoc}
   */
  public function __call($method, $args) {
    $bynder_configuration = $this->configFactory->get('bynder.settings');
    if ($bynder_configuration->get('debug')) {
      $this->loggerFactory->get('bynder')->debug('Method: %method is called with arguments: @args', [
        '%method' => $method,
        '@args' => print_r($args, TRUE),
      ]);
    }
    try {
      // TODO cache getMediaItem()?
      if (empty($args) && in_array($method, array_keys(self::CACHED_CALLS))) {
        if ($cache_item = $this->cache->get(self::CACHED_CALLS[$method], TRUE)) {
          return $cache_item->data;
        }
        else {
          $result = call_user_func_array([$this->getAssetBankManager(), $method], $args)->wait();
          $this->cache->set(self::CACHED_CALLS[$method], $result, ($this->configFactory->get('bynder.settings')->get('cache_lifetime') + $this->time->getRequestTime()));
          return $result;
        }
      }
      else {
        $result = call_user_func_array([$this->getAssetBankManager(), $method], $args)->wait();
      }
      if ($bynder_configuration->get('debug')) {
        $this->loggerFactory->get('bynder')->debug('Method: %method returns: @result', [
          '%method' => $method,
          '@result' => print_r($result, TRUE),
        ]);
      }
      return $result;
    } catch (\Exception $e) {
      if ($bynder_configuration->get('debug')) {
        $this->loggerFactory->get('bynder')
          ->error('Method: %method throws error with message: @message', [
            '%method' => $method,
            '@message' => $e->getMessage(),
          ]);
      }
      throw $e;
    }
  }

  /**
   * @return string
   */
  protected function getCallback(): string {
    $callback = Url::fromRoute(
      'bynder.oauth', [], [
      'absolute' => TRUE,
      'path_processing' => FALSE
    ]
    )
      ->toString(TRUE)
      ->getGeneratedUrl();
    return $callback;
  }

  /**
   * @return \Bynder\Api\Impl\OAuth2\Configuration
   */
  protected function getOauthConfiguration(): \Bynder\Api\Impl\OAuth2\Configuration {
    $bynder_settings = $this->configFactory->get('bynder.settings');

    $bynder_configuration = new \Bynder\Api\Impl\OAuth2\Configuration($bynder_settings->get('account_domain'), $this->getCallback(), $bynder_settings->get('client_id'), $bynder_settings->get('client_secret'), NULL, ['timeout' => $bynder_settings->get('timeout')]);
    return $bynder_configuration;
  }

}

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

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