View source  
  <?php
namespace Drupal\bynder;
use Bynder\Api\BynderApiFactory;
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 Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class BynderApi implements BynderApiInterface {
  
  const BYNDER_INTEGRATION_ID = 'a7129512-c6e3-47a3-be40-9a66503e82ed';
  
  const CID_TAGS = 'bynder_tags';
  
  const CID_METAPROPERTIES = 'bynder_metaproperties';
  
  const CID_DERIVATIVES = 'bynder_derivatives';
  
  const CACHED_CALLS = [
    'getMetaproperties' => self::CID_METAPROPERTIES,
    'getDerivatives' => self::CID_DERIVATIVES,
  ];
  
  const AUTO_UPDATED_TAGS_QUERIES = [
    [],
    [
      'limit' => 200,
      'orderBy' => 'mediaCount desc',
      'minCount' => 1,
    ],
  ];
  
  protected $bynderApi;
  
  protected $bynderConfig;
  
  protected $configFactory;
  
  protected $loggerFactory;
  
  protected $session;
  
  protected $state;
  
  protected $cache;
  
  protected $time;
  
  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;
  }
  
  public function initiateOAuthTokenRetrieval() {
    $bynder_settings = $this->configFactory
      ->get('bynder.settings');
    $bynder_configuration = [
      'consumerKey' => $bynder_settings
        ->get('consumer_key'),
      'consumerSecret' => $bynder_settings
        ->get('consumer_secret'),
      'baseUrl' => $bynder_settings
        ->get('account_domain'),
      'requestOptions' => [
        'timeout' => $bynder_settings
          ->get('timeout'),
      ],
    ];
    $this->bynderApi = BynderApiFactory::create($bynder_configuration);
    $session_data = $this->session
      ->get('bynder', []);
    foreach (explode('&', $this->bynderApi
      ->getRequestToken()
      ->wait()) as $item) {
      $value = explode('=', $item);
      $session_data['request_token'][$value[0]] = $value[1];
    }
    $this->session
      ->set('bynder', $session_data);
    $callback = Url::fromRoute('bynder.oauth', [], [
      'absolute' => TRUE,
    ])
      ->toString(TRUE)
      ->getGeneratedUrl();
    $query = [
      'oauth_token' => $session_data['request_token']['oauth_token'],
      'callback' => $callback,
    ];
    return Url::fromUri($bynder_settings
      ->get('account_domain') . '/api/v4/oauth/authorise/', array(
      'query' => $query,
      'auth' => null,
      'allow_redirects' => false,
    ));
  }
  
  public function hasAccessToken() {
    $session_data = $this->session
      ->get('bynder', []);
    
    if (empty($session_data['access_token']['oauth_token']) || empty($session_data['access_token']['oauth_token_secret'])) {
      return FALSE;
    }
    
    if (empty($session_data['config_hash']) || $session_data['config_hash'] != $this->state
      ->get('bynder_config_hash')) {
      return FALSE;
    }
    return TRUE;
  }
  
  public function finishOAuthTokenRetrieval(Request $request) {
    $bynder_settings = $this->configFactory
      ->get('bynder.settings');
    $session_data = $this->session
      ->get('bynder', []);
    $bynder_configuration = [
      'consumerKey' => $bynder_settings
        ->get('consumer_key'),
      'consumerSecret' => $bynder_settings
        ->get('consumer_secret'),
      'token' => $request->query
        ->get('oauth_token'),
      'tokenSecret' => $session_data['request_token']['oauth_token_secret'],
      'baseUrl' => $bynder_settings
        ->get('account_domain'),
      'requestOptions' => [
        'timeout' => $bynder_settings
          ->get('timeout'),
      ],
    ];
    
    $this->bynderApi = BynderApiFactory::create($bynder_configuration);
    foreach ($this->bynderApi
      ->getAccessToken()
      ->wait() as $key => $item) {
      $session_data['access_token'][$key] = $item;
    }
    unset($session_data['request_token']);
    $session_data['config_hash'] = $this->state
      ->get('bynder_config_hash');
    $this->session
      ->set('bynder', $session_data);
  }
  
  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;
  }
  
  public function getAssetBankManager() {
    $bynder_settings = $this->configFactory
      ->get('bynder.settings');
    if ($this->bynderConfig) {
      $bynder_configuration = [
        'consumerKey' => $this->bynderConfig['consumerKey'],
        'consumerSecret' => $this->bynderConfig['consumerSecret'],
        'token' => $this->bynderConfig['token'],
        'tokenSecret' => $this->bynderConfig['tokenSecret'],
        'baseUrl' => $this->bynderConfig['baseUrl'],
        'requestOptions' => [
          'timeout' => $bynder_settings
            ->get('timeout'),
        ],
      ];
    }
    else {
      $bynder_configuration = [
        'consumerKey' => $bynder_settings
          ->get('consumer_key'),
        'consumerSecret' => $bynder_settings
          ->get('consumer_secret'),
        'token' => $bynder_settings
          ->get('token'),
        'tokenSecret' => $bynder_settings
          ->get('token_secret'),
        'baseUrl' => $bynder_settings
          ->get('account_domain'),
        'requestOptions' => [
          'timeout' => $bynder_settings
            ->get('timeout'),
        ],
      ];
      
      $session_data = \Drupal::service('session')
        ->get('bynder', []);
      if (!empty($session_data['access_token']) && !empty($session_data['config_hash']) && $session_data['config_hash'] == $this->state
        ->get('bynder_config_hash')) {
        $bynder_configuration['token'] = $session_data['access_token']['oauth_token'];
        $bynder_configuration['tokenSecret'] = $session_data['access_token']['oauth_token_secret'];
      }
    }
    $this->bynderApi = BynderApiFactory::create($bynder_configuration);
    return $this->bynderApi
      ->getAssetBankManager();
  }
  
  public function setBynderConfiguration(array $config) {
    $this->bynderConfig = $config;
  }
  
  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(implode($query))] = [
        'data' => $this
          ->getAssetBankManager()
          ->getTags($query)
          ->wait(),
        'expire' => $expire,
      ];
    }
    $this->cache
      ->setMultiple($items);
    $this->state
      ->set('bynder_cache_last_update', $this->time
      ->getRequestTime());
  }
  
  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(implode($query));
        $allow_expired = FALSE;
        foreach (static::AUTO_UPDATED_TAGS_QUERIES as $candidate) {
          if (md5(implode($query)) == $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 = $this
            ->getAssetBankManager()
            ->getTags($query)
            ->wait();
          $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;
  }
  
  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();
  }
  
  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();
  }
  
  public function getAssetUsages($asset_id) {
    return $this
      ->getAssetBankManager()
      ->getUsage([
      'asset_id' => $asset_id,
    ])
      ->wait();
  }
  
  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 {
      
      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;
    }
  }
}