class RestClient in Salesforce Suite 5.0.x
Same name and namespace in other branches
- 8.4 src/Rest/RestClient.php \Drupal\salesforce\Rest\RestClient
- 8.3 src/Rest/RestClient.php \Drupal\salesforce\Rest\RestClient
Objects, properties, and methods to communicate with the Salesforce REST API.
Hierarchy
- class \Drupal\salesforce\Rest\RestClient implements RestClientInterface uses StringTranslationTrait
Expanded class hierarchy of RestClient
7 files declare their use of RestClient
- RestClientTest.php in tests/
src/ Unit/ RestClientTest.php - SalesforceCommandsBase.php in src/
Commands/ SalesforceCommandsBase.php - SalesforceMappingCommands.php in modules/
salesforce_mapping/ src/ Commands/ SalesforceMappingCommands.php - SalesforceMappingCommandsBase.php in modules/
salesforce_mapping/ src/ Commands/ SalesforceMappingCommandsBase.php - SalesforcePullCommands.php in modules/
salesforce_pull/ src/ Commands/ SalesforcePullCommands.php
1 string reference to 'RestClient'
1 service uses RestClient
File
- src/
Rest/ RestClient.php, line 25
Namespace
Drupal\salesforce\RestView source
class RestClient implements RestClientInterface {
use StringTranslationTrait;
/**
* Response object.
*
* @var \GuzzleHttp\Psr7\Response
*/
public $response;
/**
* GuzzleHttp client.
*
* @var \GuzzleHttp\ClientInterface
*/
protected $httpClient;
/**
* Config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* Salesforce API URL.
*
* @var \Drupal\Core\Url
*/
protected $url;
/**
* Salesforce immutable config object. Useful for gets.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $immutableConfig;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The cache service.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $cache;
/**
* The JSON serializer service.
*
* @var \Drupal\Component\Serialization\Json
*/
protected $json;
/**
* Auth provider manager.
*
* @var \Drupal\salesforce\SalesforceAuthProviderPluginManagerInterface
*/
protected $authManager;
/**
* Active auth provider.
*
* @var \Drupal\salesforce\SalesforceAuthProviderInterface
*/
protected $authProvider;
/**
* Active auth provider config.
*
* @var \Drupal\salesforce\Entity\SalesforceAuthConfig
*/
protected $authConfig;
/**
* Active auth token.
*
* @var \OAuth\OAuth2\Token\TokenInterface
*/
protected $authToken;
/**
* HTTP client options.
*
* @var array
*/
protected $httpClientOptions;
const CACHE_LIFETIME = 300;
const LONGTERM_CACHE_LIFETIME = 86400;
/**
* Constructor which initializes the consumer.
*
* @param \GuzzleHttp\ClientInterface $http_client
* The GuzzleHttp Client.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory service.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The cache service.
* @param \Drupal\Component\Serialization\Json $json
* The JSON serializer service.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The Time service.
* @param \Drupal\salesforce\SalesforceAuthProviderPluginManagerInterface $authManager
* Auth manager service.
*/
public function __construct(ClientInterface $http_client, ConfigFactoryInterface $config_factory, StateInterface $state, CacheBackendInterface $cache, Json $json, TimeInterface $time, SalesforceAuthProviderPluginManagerInterface $authManager) {
$this->configFactory = $config_factory;
$this->httpClient = $http_client;
$this->immutableConfig = $this->configFactory
->get('salesforce.settings');
$this->state = $state;
$this->cache = $cache;
$this->json = $json;
$this->time = $time;
$this->httpClientOptions = [];
$this->authManager = $authManager;
$this->authProvider = $authManager
->getProvider();
$this->authConfig = $authManager
->getConfig();
$this->authToken = $authManager
->getToken();
return $this;
}
public function getShortTermCacheLifetime() {
return $this->immutableConfig
->get('short_term_cache_lifetime') ?? static::CACHE_LIFETIME;
}
public function getLongTermCacheLifetime() {
return $this->immutableConfig
->get('long_term_cache_lifetime') ?? static::LONGTERM_CACHE_LIFETIME;
}
/**
* {@inheritdoc}
*/
public function isInit() {
if (!$this->authProvider || !$this->authManager) {
return FALSE;
}
// If authToken is not set, try refreshing it before failing init.
if (!$this->authToken) {
$this->authToken = $this->authManager
->refreshToken();
return isset($this->authToken);
}
return TRUE;
}
/**
* {@inheritdoc}
*/
public function apiCall($path, array $params = [], $method = 'GET', $returnObject = FALSE) {
if (!$this
->isInit()) {
throw new RestException(NULL, $this
->t('RestClient is not initialized.'));
}
if (strpos($path, '/') === 0) {
$url = $this->authProvider
->getInstanceUrl() . $path;
}
else {
$url = $this->authProvider
->getApiEndpoint() . $path;
}
try {
$this->response = new RestResponse($this
->apiHttpRequest($url, $params, $method));
} catch (RequestException $e) {
// RequestException gets thrown for any response status but 2XX.
$this->response = $e
->getResponse();
// Any exceptions besides 401 get bubbled up.
if (!$this->response || $this->response
->getStatusCode() != 401) {
throw new RestException($this->response, $e
->getMessage(), $e
->getCode(), $e);
}
}
if ($this->response
->getStatusCode() == 401) {
// The session ID or OAuth token used has expired or is invalid: refresh
// token. If refresh_token() throws an exception, or if apiHttpRequest()
// throws anything but a RequestException, let it bubble up.
$this->authToken = $this->authManager
->refreshToken();
try {
$this->response = new RestResponse($this
->apiHttpRequest($url, $params, $method));
} catch (RequestException $e) {
$this->response = $e
->getResponse();
throw new RestException($this->response, $e
->getMessage(), $e
->getCode(), $e);
}
}
if (empty($this->response) || (int) floor($this->response
->getStatusCode() / 100) != 2) {
throw new RestException($this->response, $this
->t('Unknown error occurred during API call "@call": status code @code : @reason', [
'@call' => $path,
'@code' => $this->response
->getStatusCode(),
'@reason' => $this->response
->getReasonPhrase(),
]));
}
$this
->updateApiUsage($this->response);
if ($returnObject) {
return $this->response;
}
else {
return $this->response->data;
}
}
/**
* Private helper to issue an SF API request.
*
* @param string $url
* Fully-qualified URL to resource.
* @param array $params
* Parameters to provide.
* @param string $method
* Method to initiate the call, such as GET or POST. Defaults to GET.
*
* @return \GuzzleHttp\Psr7\Response
* Response object.
*
* @throws \Exception
* @throws \GuzzleHttp\Exception\RequestException
*/
protected function apiHttpRequest($url, array $params, $method) {
if (!$this->authToken) {
throw new \Exception($this
->t('Missing OAuth Token'));
}
$headers = [
'Authorization' => 'OAuth ' . $this->authToken
->getAccessToken(),
'Content-type' => 'application/json',
];
$data = NULL;
if (!empty($params)) {
$data = $this->json
->encode($params);
}
return $this
->httpRequest($url, $data, $headers, $method);
}
/**
* {@inheritdoc}
*/
public function httpRequestRaw($url) {
if (!$this->authManager
->getToken()) {
throw new \Exception($this
->t('Missing OAuth Token'));
}
$headers = [
'Authorization' => 'OAuth ' . $this->authToken
->getAccessToken(),
'Content-type' => 'application/json',
];
$response = $this
->httpRequest($url, NULL, $headers);
return $response
->getBody()
->getContents();
}
/**
* Make the HTTP request. Wrapper around drupal_http_request().
*
* @param string $url
* Path to make request from.
* @param string $data
* The request body.
* @param array $headers
* Request headers to send as name => value.
* @param string $method
* Method to initiate the call, such as GET or POST. Defaults to GET.
*
* @return \GuzzleHttp\Psr7\Response
* Response object.
*
* @throws \GuzzleHttp\Exception\RequestException
* Request exception.
*/
protected function httpRequest($url, $data = NULL, array $headers = [], $method = 'GET') {
// Build the request, including path and headers. Internal use.
$args = NestedArray::mergeDeep($this->httpClientOptions, [
'headers' => $headers,
'body' => $data,
]);
return $this->httpClient
->{$method}($url, $args);
}
/**
* {@inheritdoc}
*/
public function setHttpClientOptions(array $options) {
$this->httpClientOptions = NestedArray::mergeDeep($this->httpClientOptions, $options);
return $this;
}
/**
* {@inheritdoc}
*/
public function setHttpClientOption($option_name, $option_value) {
$this->httpClientOptions[$option_name] = $option_value;
return $this;
}
/**
* {@inheritdoc}
*/
public function getHttpClientOptions() {
return $this->httpClientOptions;
}
/**
* {@inheritdoc}
*/
public function getHttpClientOption($option_name) {
return $this->httpClientOptions[$option_name];
}
/**
* Extract normalized error information from a RequestException.
*
* @param \GuzzleHttp\Exception\RequestException $e
* Exception object.
*
* @return array
* Error array with keys:
* * message
* * errorCode
* * fields
*/
protected function getErrorData(RequestException $e) {
$response = $e
->getResponse();
$response_body = $response
->getBody()
->getContents();
$data = $this->json
->decode($response_body);
if (!empty($data[0])) {
$data = $data[0];
}
return $data;
}
/**
* {@inheritdoc}
*/
public function getVersions($reset = FALSE) {
if (!$reset && ($cache = $this->cache
->get('salesforce:versions'))) {
return $cache->data;
}
$versions = [];
if (!$this->authProvider) {
return [];
}
try {
$id = $this->authProvider
->getIdentity();
} catch (IdentityNotFoundException $e) {
return [];
}
$url = str_replace('v{version}/', '', $id
->getUrl('rest'));
$response = new RestResponse($this
->httpRequest($url));
foreach ($response->data as $version) {
$versions[$version['version']] = $version;
}
$this->cache
->set('salesforce:versions', $versions, $this
->getRequestTime() + $this
->getLongTermCacheLifetime(), [
'salesforce',
]);
return $versions;
}
/**
* {@inheritdoc}
*/
public function getApiUsage() {
return $this->state
->get('salesforce.usage');
}
/**
* Helper to extract API Usage info from response header and write to state.
*
* @param \Drupal\salesforce\Rest\RestResponse $response
* A REST API response.
*/
protected function updateApiUsage(RestResponse $response) {
if ($limit_info = $response
->getHeader('Sforce-Limit-Info')) {
if (is_array($limit_info)) {
$limit_info = reset($limit_info);
}
$this->state
->set('salesforce.usage', $limit_info);
}
}
/**
* @defgroup salesforce_apicalls Wrapper calls around core apiCall()
*/
/**
* {@inheritdoc}
*/
public function objects(array $conditions = [
'updateable' => TRUE,
], $reset = FALSE) {
// Use the cached data if we have it.
if (!$reset && ($cache = $this->cache
->get('salesforce:objects'))) {
$result = $cache->data;
}
else {
$result = $this
->apiCall('sobjects');
$this->cache
->set('salesforce:objects', $result, $this
->getRequestTime() + $this
->getShortTermCacheLifetime(), [
'salesforce',
]);
}
// print_r($result);
$sobjects = [];
// Filter the list by conditions, and assign SF table names as array keys.
foreach ($result['sobjects'] as $key => $object) {
if (empty($object['name'])) {
print_r($object);
}
if (!empty($conditions)) {
foreach ($conditions as $condition => $value) {
if ($object[$condition] == $value) {
$sobjects[$object['name']] = $object;
}
}
}
else {
$sobjects[$object['name']] = $object;
}
}
return $sobjects;
}
/**
* {@inheritdoc}
*/
public function query(SelectQueryInterface $query) {
// $this->moduleHandler->alter('salesforce_query', $query);
// Casting $query as a string calls SelectQuery::__toString().
return new SelectQueryResult($this
->apiCall('query?q=' . (string) $query));
}
/**
* {@inheritdoc}
*/
public function queryAll(SelectQueryInterface $query) {
return new SelectQueryResult($this
->apiCall('queryAll?q=' . (string) $query));
}
/**
* {@inheritdoc}
*/
public function queryMore(SelectQueryResult $results) {
if ($results
->done()) {
return new SelectQueryResult([
'totalSize' => $results
->size(),
'done' => TRUE,
'records' => [],
]);
}
$version_path = parse_url($this->authProvider
->getApiEndpoint(), PHP_URL_PATH);
$next_records_url = str_replace($version_path, '', $results
->nextRecordsUrl());
return new SelectQueryResult($this
->apiCall($next_records_url));
}
/**
* {@inheritdoc}
*/
public function objectDescribe($name, $reset = FALSE) {
if (empty($name)) {
throw new \Exception($this
->t('No name provided to describe'));
}
if (!$reset && ($cache = $this->cache
->get('salesforce:object:' . $name))) {
return $cache->data;
}
else {
$response = new RestResponseDescribe($this
->apiCall("sobjects/{$name}/describe", [], 'GET', TRUE));
$this->cache
->set('salesforce:object:' . $name, $response, $this
->getRequestTime() + $this
->getShortTermCacheLifetime(), [
'salesforce',
]);
return $response;
}
}
/**
* {@inheritdoc}
*/
public function objectCreate($name, array $params) {
$response = $this
->apiCall("sobjects/{$name}", $params, 'POST', TRUE);
$data = $response->data;
return new SFID($data['id']);
}
/**
* {@inheritdoc}
*/
public function objectUpsert($name, $key, $value, array $params) {
// If key is set, remove from $params to avoid UPSERT errors.
if (isset($params[$key])) {
unset($params[$key]);
}
$response = $this
->apiCall("sobjects/{$name}/{$key}/{$value}", $params, 'PATCH', TRUE);
// On update, upsert method returns an empty body. Retreive object id, so
// that we can return a consistent response.
if ($response
->getStatusCode() == 204) {
// We need a way to allow callers to distinguish updates and inserts. To
// that end, cache the original response and reset it after fetching the
// ID.
$this->original_response = $response;
$sf_object = $this
->objectReadbyExternalId($name, $key, $value);
return $sf_object
->id();
}
$data = $response->data;
return new SFID($data['id']);
}
/**
* {@inheritdoc}
*/
public function objectUpdate($name, $id, array $params) {
$this
->apiCall("sobjects/{$name}/{$id}", $params, 'PATCH');
}
/**
* {@inheritdoc}
*/
public function objectRead($name, $id) {
return new SObject($this
->apiCall("sobjects/{$name}/{$id}"));
}
/**
* {@inheritdoc}
*/
public function objectReadbyExternalId($name, $field, $value) {
return new SObject($this
->apiCall("sobjects/{$name}/{$field}/{$value}"));
}
/**
* {@inheritdoc}
*/
public function objectDelete($name, $id, $throw_exception = FALSE) {
try {
$this
->apiCall("sobjects/{$name}/{$id}", [], 'DELETE');
} catch (RequestException $e) {
if ($throw_exception || $e
->getResponse()
->getStatusCode() != 404) {
throw $e;
}
}
}
/**
* {@inheritdoc}
*/
public function getDeleted($type, $startDate, $endDate) {
return $this
->apiCall("sobjects/{$type}/deleted/?start={$startDate}&end={$endDate}");
}
/**
* {@inheritdoc}
*/
public function listResources() {
return new RestResponseResources($this
->apiCall('', [], 'GET', TRUE));
}
/**
* {@inheritdoc}
*/
public function getUpdated($name, $start = NULL, $end = NULL) {
if (empty($start)) {
$start = strtotime('-29 days');
}
$start = urlencode(gmdate(DATE_ATOM, $start));
if (empty($end)) {
$end = time();
}
$end = urlencode(gmdate(DATE_ATOM, $end));
return $this
->apiCall("sobjects/{$name}/updated/?start={$start}&end={$end}");
}
/**
* {@inheritdoc}
*/
public function getRecordTypes($name = NULL, $reset = FALSE) {
if (!$reset && ($cache = $this->cache
->get('salesforce:record_types'))) {
$record_types = $cache->data;
}
else {
$query = new SelectQuery('RecordType');
$query->fields = [
'Id',
'Name',
'DeveloperName',
'SobjectType',
];
$result = $this
->query($query);
$record_types = [];
foreach ($result
->records() as $rt) {
$record_types[$rt
->field('SobjectType')][$rt
->field('DeveloperName')] = $rt;
}
$this->cache
->set('salesforce:record_types', $record_types, $this
->getRequestTime() + $this
->getShortTermCacheLifetime(), [
'salesforce',
]);
}
if ($name != NULL) {
if (!isset($record_types[$name])) {
return FALSE;
}
return $record_types[$name];
}
return $record_types ?: FALSE;
}
/**
* {@inheritdoc}
*/
public function getRecordTypeIdByDeveloperName($name, $devname, $reset = FALSE) {
$record_types = $this
->getRecordTypes($name, $reset);
if (empty($record_types[$devname])) {
return FALSE;
}
return $record_types[$devname]
->id();
}
/**
* {@inheritdoc}
*/
public function getObjectTypeName(SFID $id) {
$prefix = substr((string) $id, 0, 3);
$describe = $this
->objects();
foreach ($describe as $object) {
if ($prefix == $object['keyPrefix']) {
return $object['name'];
}
}
return FALSE;
}
/**
* Returns REQUEST_TIME.
*
* @return int
* The REQUEST_TIME server variable.
*/
protected function getRequestTime() {
return $this->time
->getRequestTime();
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
RestClient:: |
protected | property | Active auth provider config. | |
RestClient:: |
protected | property | Auth provider manager. | |
RestClient:: |
protected | property | Active auth provider. | |
RestClient:: |
protected | property | Active auth token. | |
RestClient:: |
protected | property | The cache service. | |
RestClient:: |
protected | property | Config factory service. | |
RestClient:: |
protected | property | GuzzleHttp client. | |
RestClient:: |
protected | property | HTTP client options. | |
RestClient:: |
protected | property | Salesforce immutable config object. Useful for gets. | |
RestClient:: |
protected | property | The JSON serializer service. | |
RestClient:: |
public | property | Response object. | |
RestClient:: |
protected | property | The state service. | |
RestClient:: |
protected | property | Salesforce API URL. | |
RestClient:: |
public | function |
Make a call to the Salesforce REST API. Overrides RestClientInterface:: |
1 |
RestClient:: |
protected | function | Private helper to issue an SF API request. | |
RestClient:: |
constant | |||
RestClient:: |
public | function |
Get the api usage, as returned in the most recent API request header. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Retrieves objects deleted within the given timeframe. Overrides RestClientInterface:: |
|
RestClient:: |
protected | function | Extract normalized error information from a RequestException. | |
RestClient:: |
public | function |
Getter for a single, named HTTP client option. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Getter for HTTP client options. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Getter for long term cache lifetime. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Utility function to determine object type for given SFID. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Given a DeveloperName and SObject Name, return SFID of the RecordType. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Retrieve all record types for this org. Overrides RestClientInterface:: |
1 |
RestClient:: |
protected | function | Returns REQUEST_TIME. | |
RestClient:: |
public | function |
Getter for short term cache lifetime. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Return a list of SFIDs for the given object for the given timeframe. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Wrapper for "Versions" resource to list information about API releases. Overrides RestClientInterface:: |
|
RestClient:: |
protected | function | Make the HTTP request. Wrapper around drupal_http_request(). | |
RestClient:: |
public | function |
Return raw response content from given URL. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Check if the client is ready to perform API calls. Overrides RestClientInterface:: |
1 |
RestClient:: |
public | function |
Return a list of available resources for the configured API version. Overrides RestClientInterface:: |
1 |
RestClient:: |
constant | |||
RestClient:: |
public | function |
Create a new object of the given type. Overrides RestClientInterface:: |
1 |
RestClient:: |
public | function |
Delete a Salesforce object. Overrides RestClientInterface:: |
1 |
RestClient:: |
public | function |
Retrieve all the metadata for an object. Overrides RestClientInterface:: |
1 |
RestClient:: |
public | function |
Return a fullly loaded Salesforce object. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Return a full loaded Salesforce object from External ID. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Available objects and their metadata for your organization's data. Overrides RestClientInterface:: |
1 |
RestClient:: |
public | function |
Update an existing object. Overrides RestClientInterface:: |
1 |
RestClient:: |
public | function |
Create new records or update existing records. Overrides RestClientInterface:: |
1 |
RestClient:: |
public | function |
Use SOQL to get objects based on query string. Overrides RestClientInterface:: |
1 |
RestClient:: |
public | function |
Same as ::query(), but also returns deleted or archived records. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Given a select query result, fetch the next results set, if it exists. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Set a single Guzzle HTTP client option. Overrides RestClientInterface:: |
|
RestClient:: |
public | function |
Set options for Guzzle HTTP client. Overrides RestClientInterface:: |
|
RestClient:: |
protected | function | Helper to extract API Usage info from response header and write to state. | |
RestClient:: |
public | function | Constructor which initializes the consumer. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |