diff --git a/composer.json b/composer.json index 9a5ba6b..7004637 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "codeclimate/php-test-reporter": "dev-master" }, "require": { - "php": ">=7.1", + "php": ">=7.0", "psr/http-message": "^1.0", "guzzlehttp/guzzle": "^6.3", "guzzlehttp/psr7": "^1.4" diff --git a/src/Rest/GuzzleRestClient.php b/src/Rest/GuzzleRestClient.php index 4a6c016..97f996e 100644 --- a/src/Rest/GuzzleRestClient.php +++ b/src/Rest/GuzzleRestClient.php @@ -1,8 +1,12 @@ setBaseUriForRestClient($baseUri); } - public function setBaseUriForRestClient(string $baseUri): void + /** + * Set base uri for client + * + * @param string $baseUri base uri + * + * @return void + */ + public function setBaseUriForRestClient(string $baseUri) { if (!$this->containsTrailingSlash($baseUri)) { $baseUri .= '/'; @@ -34,68 +50,136 @@ public function setBaseUriForRestClient(string $baseUri): void $this->client = new \GuzzleHttp\Client($config); } + /** + * Get method + * + * @param string $path path + * @param array $queryParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ public function get( string $path, array $queryParameters = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { return $this->client->request( 'GET', $path, [ 'timeout' => $timeoutSeconds, 'headers' => $headers, - 'query' => $queryParameters, - 'http_errors' => false, + 'query' => $queryParameters ] ); } + /** + * Post method + * + * @param string $path path + * @param array $formParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ public function post( string $path, array $formParameters = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { return $this->client->request( 'POST', $path, [ 'timeout' => $timeoutSeconds, 'headers' => $headers, - 'form_params' => $formParameters, - 'http_errors' => false, + 'form_params' => $formParameters + ] + ); + } + + /** + * Delete method + * + * @param string $path path + * @param array $formParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function delete( + string $path, + array $formParameters = [], + array $headers = [], + float $timeoutSeconds = null + ) { + return $this->client->request( + 'DELETE', + $path, + [ + 'timeout' => $timeoutSeconds, + 'headers' => $headers, + 'form_params' => $formParameters ] ); } + /** + * Post method JSON formatted + * + * @param string $path path + * @param array $jsonArray parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ public function postJson( string $path, array $jsonArray = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { $headers['Content-Type'] = 'application/json'; - return $this->client->request( 'POST', $path, [ 'timeout' => $timeoutSeconds, 'headers' => $headers, - 'json' => $jsonArray, - 'http_errors' => false, + 'json' => $jsonArray ] ); } + /** + * Patch method JSON formatted + * + * @param string $path path + * @param array $jsonArray parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ public function patchJson( string $path, array $jsonArray = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { $headers['Content-Type'] = 'application/json'; return $this->client->request( @@ -104,13 +188,49 @@ public function patchJson( [ 'timeout' => $timeoutSeconds, 'headers' => $headers, - 'json' => $jsonArray, - 'http_errors' => false, + 'json' => $jsonArray + ] + ); + } + + /** + * Put method CSV formatted + * + * @param string $path path + * @param string $filePath file path + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function putCsv( + string $path, + string $filePath, + array $headers = [], + float $timeoutSeconds = null + ) { + $headers['Content-Type'] = 'text/csv'; + + return $this->client->request( + 'PUT', + $path, + [ + 'timeout' => $timeoutSeconds, + 'headers' => $headers, + 'body' => fopen($filePath, 'r') ] ); } - private function containsTrailingSlash(string $baseUri): bool + /** + * Check if contains trailing slash + * + * @param string $baseUri base uri + * + * @return bool + */ + private function containsTrailingSlash(string $baseUri) { return substr($baseUri, -1) === '/'; } diff --git a/src/Rest/OAuthAccessToken.php b/src/Rest/OAuthAccessToken.php index 6a55a5b..2917e19 100644 --- a/src/Rest/OAuthAccessToken.php +++ b/src/Rest/OAuthAccessToken.php @@ -1,6 +1,11 @@ tokenType = $tokenType; $this->accessToken = $accessToken; @@ -32,42 +47,82 @@ public function __construct( $this->expiresAt = $expiresAt; } - public function getTokenType(): string + /** + * Get token type + * + * @return string + */ + public function getTokenType() { return $this->tokenType; } - public function getAccessToken(): string + /** + * Get access token + * + * @return string + */ + public function getAccessToken() { return $this->accessToken; } - public function getRefreshToken(): ?string + /** + * Get refresh token + * + * @return null|string + */ + public function getRefreshToken() { return $this->refreshToken; } - public function getInstanceUrl(): string + /** + * Get instance url + * + * @return string + */ + public function getInstanceUrl() { return $this->instanceUrl; } - public function getHeaderString(): string + /** + * Get header string + * + * @return string + */ + public function getHeaderString() { return $this->tokenType . ' ' . $this->accessToken; } - public function getResourceOwnerUrl(): string + /** + * Get resource owner url + * + * @return string + */ + public function getResourceOwnerUrl() { return $this->resourceOwnerUrl; } - public function getExpiresAt(): ?int + /** + * Get expires at value + * + * @return int|null + */ + public function getExpiresAt() { return $this->expiresAt; } - public function isExpired(): bool + /** + * Check if expired + * + * @return bool + */ + public function isExpired() { if ($this->expiresAt === null) { return false; diff --git a/src/Rest/OAuthRestClient.php b/src/Rest/OAuthRestClient.php index 0f3c0c8..5e1a5c7 100644 --- a/src/Rest/OAuthRestClient.php +++ b/src/Rest/OAuthRestClient.php @@ -4,6 +4,11 @@ use Psr\Http\Message\ResponseInterface; use Throwable; +/** + * Class OAuthRestClient + * + * @package EventFarm\Restforce\Rest + */ final class OAuthRestClient implements RestClientInterface { const TOKEN_TYPE = 'Bearer'; @@ -22,14 +27,25 @@ final class OAuthRestClient implements RestClientInterface /** @var null|string */ private $password; + /** + * OAuthRestClient constructor. + * + * @param SalesforceRestClientInterface $apiRestClient api rest client + * @param RestClientInterface $authRestClient auth rest client + * @param string $clientId client id + * @param string $clientSecret client secret + * @param string|null $username username + * @param string|null $password password + * @param OAuthAccessToken|null $oAuthAccessToken access token + */ public function __construct( SalesforceRestClientInterface $apiRestClient, RestClientInterface $authRestClient, string $clientId, string $clientSecret, - ?string $username = null, - ?string $password = null, - ?OAuthAccessToken $oAuthAccessToken = null + string $username = null, + string $password = null, + OAuthAccessToken $oAuthAccessToken = null ) { $this->apiRestClient = $apiRestClient; $this->authRestClient = $authRestClient; @@ -40,12 +56,22 @@ public function __construct( $this->password = $password; } + /** + * Get method + * + * @param string $path path + * @param array $queryParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ public function get( string $path, array $queryParameters = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { $this->setParamsFromAccessToken(); return $this->apiRestClient->get( $path, @@ -55,12 +81,22 @@ public function get( ); } + /** + * Post method + * + * @param string $path path + * @param array $formParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ public function post( string $path, array $formParameters = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { $this->setParamsFromAccessToken(); return $this->apiRestClient->post( $path, @@ -70,12 +106,47 @@ public function post( ); } + /** + * Post method + * + * @param string $path path + * @param array $formParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ + public function delete( + string $path, + array $formParameters = [], + array $headers = [], + float $timeoutSeconds = null + ) { + $this->setParamsFromAccessToken(); + return $this->apiRestClient->delete( + $path, + $formParameters, + $this->getAuthorizationHeader($headers), + $timeoutSeconds + ); + } + + /** + * Post method JSON formatted + * + * @param string $path path + * @param array $jsonArray parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ public function postJson( string $path, array $jsonArray = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { $this->setParamsFromAccessToken(); return $this->apiRestClient->postJson( $path, @@ -85,12 +156,22 @@ public function postJson( ); } + /** + * Patch method JSON formatted + * + * @param string $path path + * @param array $jsonArray parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ public function patchJson( string $path, array $jsonArray = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { $this->setParamsFromAccessToken(); return $this->apiRestClient->patchJson( $path, @@ -100,13 +181,49 @@ public function patchJson( ); } - private function setParamsFromAccessToken(): void + /** + * Put method CSV formatted + * + * @param string $path path + * @param string $filePath file path + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ + public function putCsv( + string $path, + string $filePath, + array $headers = [], + float $timeoutSeconds = null + ) + { + $this->setParamsFromAccessToken(); + return $this->apiRestClient->putCsv( + $path, + $filePath, + $this->getAuthorizationHeader($headers), + $timeoutSeconds + ); + } + + /** + * Set params from access token + * + * @return void + */ + private function setParamsFromAccessToken() { $this->apiRestClient->setBaseUriForRestClient($this->getOAuthAccessToken()->getInstanceUrl()); $this->apiRestClient->setResourceOwnerUrl($this->getOAuthAccessToken()->getResourceOwnerUrl()); } - private function getOAuthAccessToken(): OAuthAccessToken + /** + * Get OAuth access token + * + * @return OAuthAccessToken + */ + private function getOAuthAccessToken() { if ($this->oAuthAccessToken === null) { $this->oAuthAccessToken = $this->getNewToken(); @@ -125,10 +242,16 @@ private function getOAuthAccessToken(): OAuthAccessToken $this->oAuthAccessToken = $this->getNewToken(); } } - return $this->oAuthAccessToken; } + /** + * Get authorization header + * + * @param array $headers headers + * + * @return array + */ private function getAuthorizationHeader(array $headers = []) { return array_merge( @@ -139,7 +262,12 @@ private function getAuthorizationHeader(array $headers = []) ); } - private function getClientCredentialsAccessToken(): OAuthAccessToken + /** + * Get client credentials access token + * + * @return OAuthAccessToken + */ + private function getClientCredentialsAccessToken() { $response = $this->authRestClient->post('/services/oauth2/token', [ 'grant_type' => 'client_credentials', @@ -150,7 +278,12 @@ private function getClientCredentialsAccessToken(): OAuthAccessToken return $this->getOAuthAccessTokenFromResponse($response); } - private function getPasswordAccessToken(): OAuthAccessToken + /** + * Get password access token + * + * @return OAuthAccessToken + */ + private function getPasswordAccessToken() { $response = $this->authRestClient->post('/services/oauth2/token', [ 'grant_type' => 'password', @@ -163,7 +296,14 @@ private function getPasswordAccessToken(): OAuthAccessToken return $this->getOAuthAccessTokenFromResponse($response); } - private function getRefreshToken(string $refreshToken): OAuthAccessToken + /** + * Get refresh token + * + * @param string $refreshToken refresh token + * + * @return OAuthAccessToken + */ + private function getRefreshToken(string $refreshToken) { $response = $this->authRestClient->post('/services/oauth2/token', [ 'grant_type' => 'refresh_token', @@ -176,21 +316,23 @@ private function getRefreshToken(string $refreshToken): OAuthAccessToken } /** - * @param ResponseInterface $response + * Get OAuth access token from response + * + * @param ResponseInterface $response response + * * @return OAuthAccessToken * @throws OAuthRestClientException */ - private function getOAuthAccessTokenFromResponse(ResponseInterface $response): OAuthAccessToken + private function getOAuthAccessTokenFromResponse(ResponseInterface $response) { if ($response->getStatusCode() !== 200) { throw OAuthRestClientException::unableToLoadAccessToken(); } - $response = json_decode($response->getBody()->__toString(), true); + $response = json_decode($response->getBody(), true); try { $resourceOwnerUrl = $response['id']; - return new OAuthAccessToken( self::TOKEN_TYPE, $response['access_token'], @@ -204,7 +346,12 @@ private function getOAuthAccessTokenFromResponse(ResponseInterface $response): O } } - private function getNewToken(): OAuthAccessToken + /** + * Get new token + * + * @return OAuthAccessToken + */ + private function getNewToken() { if ($this->username === null && $this->password === null) { return $this->getClientCredentialsAccessToken(); diff --git a/src/Rest/OAuthRestClientException.php b/src/Rest/OAuthRestClientException.php index a535690..9114177 100644 --- a/src/Rest/OAuthRestClientException.php +++ b/src/Rest/OAuthRestClientException.php @@ -3,8 +3,18 @@ use Exception; +/** + * Class OAuthRestClientException + * + * @package EventFarm\Restforce\Rest + */ class OAuthRestClientException extends Exception { + /** + * Triggered when access token can't be loaded + * + * @return OAuthRestClientException + */ public static function unableToLoadAccessToken() { return new self('Unable to load access token'); diff --git a/src/Rest/RestClientInterface.php b/src/Rest/RestClientInterface.php index f3530ce..7d87426 100644 --- a/src/Rest/RestClientInterface.php +++ b/src/Rest/RestClientInterface.php @@ -1,35 +1,95 @@ restClient = $restClient; $this->apiVersion = $apiVersion; } - public function setResourceOwnerUrl(string $resourceOwnerUrl): void + /** + * Set resource owner url + * + * @param string $resourceOwnerUrl resource owner url + * + * @return void + */ + public function setResourceOwnerUrl(string $resourceOwnerUrl) { $this->resourceOwnerUrl = $resourceOwnerUrl; } - public function setBaseUriForRestClient(string $baseUri): void + /** + * Set base uri for rest client + * + * @param string $baseUri base uri + * + * @return void + */ + public function setBaseUriForRestClient(string $baseUri) { $this->restClient->setBaseUriForRestClient($baseUri); } + /** + * Get method + * + * @param string $path path + * @param array $queryParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ public function get( string $path, array $queryParameters = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { return $this->restClient->get( $this->constructUrl($path), $queryParameters, @@ -43,12 +79,23 @@ public function get( ); } + /** + * Post method + * + * @param string $path path + * @param array $formParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ public function post( string $path, array $formParameters = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { return $this->restClient->post( $this->constructUrl($path), $formParameters, @@ -57,12 +104,48 @@ public function post( ); } + /** + * Post method + * + * @param string $path path + * @param array $formParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function delete( + string $path, + array $formParameters = [], + array $headers = [], + float $timeoutSeconds = null + ) { + return $this->restClient->delete( + $this->constructUrl($path), + $formParameters, + $headers, + $timeoutSeconds + ); + } + + /** + * Post method JSON formatted + * + * @param string $path path + * @param array $jsonArray parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ public function postJson( string $path, array $jsonArray = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { return $this->restClient->postJson( $this->constructUrl($path), $jsonArray, @@ -71,12 +154,23 @@ public function postJson( ); } + /** + * Patch method JSON formatted + * + * @param string $path path + * @param array $jsonArray parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ public function patchJson( string $path, array $jsonArray = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface { + float $timeoutSeconds = null + ) { return $this->restClient->patchJson( $this->constructUrl($path), $jsonArray, @@ -85,7 +179,40 @@ public function patchJson( ); } - private function constructUrl(string $endpoint): string + /** + * Put method CSV formatted + * + * @param string $path path + * @param string $filePath file path + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function putCsv( + string $path, + string $filePath, + array $headers = [], + float $timeoutSeconds = null + ) + { + return $this->restClient->putCsv( + $this->constructUrl($path), + $filePath, + $headers, + $timeoutSeconds + ); + } + + /** + * Construct url for salesforce + * + * @param string $endpoint endpoint + * + * @return bool|string + */ + private function constructUrl(string $endpoint) { if ($endpoint === Restforce::USER_INFO_ENDPOINT) { return $this->resourceOwnerUrl; diff --git a/src/Rest/SalesforceRestClientInterface.php b/src/Rest/SalesforceRestClientInterface.php index ae783e5..cb80227 100644 --- a/src/Rest/SalesforceRestClientInterface.php +++ b/src/Rest/SalesforceRestClientInterface.php @@ -3,36 +3,130 @@ use Psr\Http\Message\ResponseInterface; +/** + * Interface SalesforceRestClientInterface + * + * @package EventFarm\Restforce\Rest + */ interface SalesforceRestClientInterface extends RestClientInterface { - public function setResourceOwnerUrl(string $resourceOwnerUrl): void; - public function setBaseUriForRestClient(string $baseUri): void; + /** + * Set resource owner url + * + * @param string $resourceOwnerUrl resource owner url + * + * @return mixed + */ + public function setResourceOwnerUrl(string $resourceOwnerUrl); + /** + * Set base uri for rest client + * + * @param string $baseUri base uri + * + * @return mixed + */ + public function setBaseUriForRestClient(string $baseUri); + + /** + * Get method + * + * @param string $path path + * @param array $queryParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ public function get( string $path, array $queryParameters = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface; + float $timeoutSeconds = null + ); + /** + * Post method + * + * @param string $path path + * @param array $formParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ public function post( string $path, array $formParameters = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface; + float $timeoutSeconds = null + ); + + /** + * Delete method + * + * @param string $path path + * @param array $formParameters parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ + public function delete( + string $path, + array $formParameters = [], + array $headers = [], + float $timeoutSeconds = null + ); + /** + * Post method JSON formatted + * + * @param string $path path + * @param array $jsonArray parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ public function postJson( string $path, array $jsonArray = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface; + float $timeoutSeconds = null + ); + /** + * Patch method JSON formatted + * + * @param string $path path + * @param array $jsonArray parameters + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ public function patchJson( string $path, array $jsonArray = [], array $headers = [], - ?float $timeoutSeconds = null - ): ResponseInterface; + float $timeoutSeconds = null + ); + + /** + * Put method CSV formatted + * + * @param string $path path + * @param string $filePath file path + * @param array $headers headers + * @param float|null $timeoutSeconds timeout + * + * @return mixed + */ + public function putCsv( + string $path, + string $filePath, + array $headers = [], + float $timeoutSeconds = null + ); } diff --git a/src/Restforce.php b/src/Restforce.php index 3975712..6237954 100644 --- a/src/Restforce.php +++ b/src/Restforce.php @@ -1,18 +1,28 @@ apiEndpoint = $apiEndpoint; $this->apiVersion = $apiVersion; $this->clientId = $clientId; $this->clientSecret = $clientSecret; @@ -53,28 +84,168 @@ public function __construct( $this->password = $password; } - public function create(string $sobjectType, array $data): ResponseInterface + /** + * Create method + * + * @param string $sobjectType object type + * @param array $data data + * + * @return mixed + */ + public function create(string $sobjectType, array $data) { $uri = 'sobjects/' . $sobjectType; return $this->getOAuthRestClient()->postJson($uri, $data); } - public function update(string $sobjectType, string $sobjectId, array $data): ResponseInterface + /** + * Create bulk job + * + * @param string $object object to work with + * @param string $operation operation + * @param array $headerColumnList column names for header + * + * @return string + * @throws \Exception + */ + public function createJob(string $object, string $operation, $headerColumnList) + { + if (empty($headerColumnList)) { + throw new \Exception( + 'header columns are missing on csv file for operation ' . $operation . ' on object ' . $object + ); + } + $uri = 'jobs/ingest'; + + $job = $this->getOAuthRestClient()->postJson($uri, [ + 'operation' => $operation, + 'object' => $object, + 'contentType' => 'CSV' + ]); + + $jobResponse = json_decode($job->getBody()); + + if (!$jobResponse->id) { + throw new \Exception( + 'An error occurred while creating bulk job of type ' . $operation . ' on object ' . $object + ); + } + + $fp = fopen($jobResponse->id . self::CSV_EXTENSION, self::FILE_WRITE); + fputcsv($fp, $headerColumnList); + fclose($fp); + + return $jobResponse->id; + } + + /** + * Add record to bulk job (csv file) + * + * @param string $jobId job id + * @param array $dataHash data hash + * + * @return void + * @throws \Exception + */ + public function addRecordLineToJob(string $jobId, array $dataHash) + { + $filePath = $jobId . self::CSV_EXTENSION; + + if (!file_exists($filePath)) { + throw new \Exception('File ' . $filePath . ' has not been found. Cannot add batch to job ' . $jobId); + } + + $fp = fopen($filePath, self::FILE_APPEND); + fputcsv($fp, array_values($dataHash)); + + fclose($fp); + } + + /** + * Execute bulk job + * + * @param string $jobId job id + * + * @return mixed + */ + public function executeJob(string $jobId) + { + $uri = 'jobs/ingest/' . $jobId . '/batches'; + return $this->getOAuthRestClient()->putCsv($uri, $jobId . self::CSV_EXTENSION); + } + + /** + * Check bulk job status + * + * @param string $jobId job id + * + * @return mixed + */ + public function checkJob(string $jobId) + { + $uri = 'jobs/ingest/' . $jobId; + return $this->getOAuthRestClient()->get($uri); + } + + /** + * Close bulk job + * + * @param string $jobId job id + * + * @return void + */ + public function closeJob(string $jobId) + { + $uri = 'jobs/ingest/' . $jobId; + + $this->getOAuthRestClient()->patchJson($uri, [ + 'state' => 'UploadComplete' + ]); + + unlink($jobId . self::CSV_EXTENSION); + } + + /** + * Update method + * + * @param string $sobjectType object type + * @param string $sobjectId object id + * @param array $data data + * + * @return mixed + */ + public function update(string $sobjectType, string $sobjectId, array $data) { $uri = 'sobjects/' . $sobjectType . '/' . $sobjectId; return $this->getOAuthRestClient()->patchJson($uri, $data); } - public function describe(string $sobject): ResponseInterface + /** + * Describe method + * + * @param string $sobject object + * + * @return mixed + */ + public function describe(string $sobject) { $uri = 'sobjects/' . $sobject . '/describe'; return $this->getOAuthRestClient()->get($uri); } - public function find(string $sobjectType, string $sobjectId, array $fields = []): ResponseInterface + /** + * Find method + * + * @param string $sobjectType object type + * @param string $sobjectId object id + * @param array $fields fields + * + * @return mixed + */ + public function find(string $sobjectType, string $sobjectId, array $fields = []) { $uri = 'sobjects/' . $sobjectType . '/' . $sobjectId; @@ -88,37 +259,108 @@ public function find(string $sobjectType, string $sobjectId, array $fields = []) return $this->getOAuthRestClient()->get($uri, $queryParams); } - public function limits(): ResponseInterface + /** + * Parameterized search method + * + * @param string $sobjectType object type + * @param string $search search query + * @param array $fields fields + * @param string|null $whereQuery where query + * + * @return mixed + */ + public function parameterizedSearch( + string $sobjectType, + string $search, + array $fields = [], + string $whereQuery = null + ) { + $uri = 'parameterizedSearch'; + + return $this->getOAuthRestClient()->postJson($uri, [ + "q" => $search, + "fields" => $fields, + "sobjects" => [ + [ + "name" => $sobjectType, + "where" => $whereQuery + ] + ] + ]); + } + + /** + * Limits method + * + * @return mixed + */ + public function limits() { return $this->getOAuthRestClient()->get('/limits'); } - public function getNext(string $url): ResponseInterface + /** + * GetNext method + * + * @param string $url url + * + * @return mixed + */ + public function getNext(string $url) { return $this->getOAuthRestClient()->get($url); } - public function query(string $queryString): ResponseInterface + /** + * Query method + * + * @param string $queryString query string + * + * @return mixed + */ + public function query(string $queryString) { return $this->getOAuthRestClient()->get('query', [ 'q' => $queryString, ]); } - public function userInfo(): ResponseInterface + /** + * Query method + * + * @param string $queryString query string + * + * @return mixed + */ + public function delete(string $queryString) + { + return $this->getOAuthRestClient()->delete('sobjects/' . $queryString); + } + + /** + * UserInfo method + * + * @return mixed + */ + public function userInfo() { return $this->getOAuthRestClient()->get(self::USER_INFO_ENDPOINT); } - private function getOAuthRestClient(): RestClientInterface + /** + * Get OAuth rest client + * + * @return OAuthRestClient|null + */ + private function getOAuthRestClient() { if ($this->oAuthRestClient === null) { $this->oAuthRestClient = new OAuthRestClient( new SalesforceRestClient( - new GuzzleRestClient('https://na1.salesforce.com'), + new GuzzleRestClient($this->apiEndpoint), $this->apiVersion ), - new GuzzleRestClient('https://login.salesforce.com'), + new GuzzleRestClient($this->apiEndpoint), $this->clientId, $this->clientSecret, $this->username, @@ -126,7 +368,6 @@ private function getOAuthRestClient(): RestClientInterface $this->accessToken ); } - return $this->oAuthRestClient; } } diff --git a/src/RestforceException.php b/src/RestforceException.php index f866c8d..cf52522 100644 --- a/src/RestforceException.php +++ b/src/RestforceException.php @@ -3,13 +3,30 @@ use Throwable; +/** + * Class RestforceException + * + * @package EventFarm\Restforce + */ class RestforceException extends \Exception { + /** + * RestforceException constructor. + * + * @param string $message message + * @param int $code error code + * @param Throwable|null $previous previous + */ public function __construct(string $message, int $code = 500, Throwable $previous = null) { parent::__construct($message, $code, $previous); } + /** + * Triggered when missing required fields + * + * @return RestforceException + */ public static function minimumRequiredFieldsNotMet() { return new self('Restforce needs either an OAuthToken or User/PW combo to start authenticate'); diff --git a/src/RestforceInterface.php b/src/RestforceInterface.php index c13b4dd..5cd7ce1 100644 --- a/src/RestforceInterface.php +++ b/src/RestforceInterface.php @@ -3,14 +3,100 @@ use Psr\Http\Message\ResponseInterface; +/** + * Interface RestforceInterface + * + * @package EventFarm\Restforce + */ interface RestforceInterface { - public function userInfo(): ResponseInterface; - public function limits(): ResponseInterface; - public function query(string $soqlQuery): ResponseInterface; - public function create(string $sobjectType, array $data): ResponseInterface; - public function update(string $sobjectType, string $sobjectId, array $data): ResponseInterface; - public function describe(string $sobjectType): ResponseInterface; - public function find(string $sobjectType, string $sobjectId, array $fields = []): ResponseInterface; - public function getNext(string $url): ResponseInterface; + /** + * UserInfo method + * + * @return mixed + */ + public function userInfo(); + + /** + * Limits method + * + * @return mixed + */ + public function limits(); + + /** + * Query method + * + * @param string $soqlQuery query + * + * @return mixed + */ + public function query(string $soqlQuery); + + /** + * Create method + * + * @param string $sobjectType object type + * @param array $data data + * + * @return mixed + */ + public function create(string $sobjectType, array $data); + + /** + * Update method + * + * @param string $sobjectType object type + * @param string $sobjectId object id + * @param array $data data + * + * @return mixed + */ + public function update(string $sobjectType, string $sobjectId, array $data); + + /** + * Describe method + * + * @param string $sobjectType object type + * + * @return mixed + */ + public function describe(string $sobjectType); + + /** + * Find method + * + * @param string $sobjectType object type + * @param string $sobjectId object id + * @param array $fields fields + * + * @return mixed + */ + public function find(string $sobjectType, string $sobjectId, array $fields = []); + + /** + * GetNext method + * + * @param string $url url + * + * @return mixed + */ + public function getNext(string $url); + + /** + * ParameterizedSearch method + * + * @param string $sobjectType object type + * @param string $search search query + * @param array $fields fields + * @param string|null $whereQuery where query + * + * @return mixed + */ + public function parameterizedSearch( + string $sobjectType, + string $search, + array $fields = [], + string $whereQuery = null + ); } diff --git a/src/Types/Account.php b/src/Types/Account.php new file mode 100644 index 0000000..f3819a0 --- /dev/null +++ b/src/Types/Account.php @@ -0,0 +1,44 @@ + + */ +class Account +{ + const SF_OBJECT = 'Account'; + + const SF_ID = 'Id'; + const SF_NAME = 'Name'; + const SF_CORPORATE_NAME = 'Company_s_Corporate_Name__c'; + const SF_COUNTRY = 'Account_Country__c'; + const SF_CITY = 'Account_City__c'; + const SF_STREET = 'Account_Street__c'; + const SF_ZIPCODE = 'Account_Zip_Postal_code__c'; + const SF_STATUS = 'Global_Account_Status__c'; + const SF_SAT_STATUS = 'SAT_validation__c'; + const SF_NUMBER_ROOMING_LIST_CONTACT = 'Number_of_Rooming_List_Contact__c'; + const SF_NUMBER_COMMERCIAL_CONTACT = 'Number_of_commercial_contact__c'; + + const SF_ACTIVE_STATUS = 'Active Account'; + const SF_INACTIVE_STATUS = 'Inactive Account'; + + const SF_SAT_ACTIVE_STATUS = 'Approved'; + const SF_SAT_INACTIVE_STATUS = 'Refused'; + + /** + * Query fields available in SF for an Account + */ + const SF_FIELD_LIST = [ + self::SF_ID, + self::SF_NAME, + self::SF_COUNTRY, + self::SF_CITY, + self::SF_STREET, + self::SF_ZIPCODE + ]; +} \ No newline at end of file diff --git a/src/Types/BongCity.php b/src/Types/BongCity.php new file mode 100644 index 0000000..d4c7e95 --- /dev/null +++ b/src/Types/BongCity.php @@ -0,0 +1,29 @@ + + */ +class BongCity +{ + const SF_OBJECT = 'BongCity__c'; + + const SF_ID = 'Id'; + const SF_NAME = 'Name'; + const SF_ID_BONG = 'ID_BONG__c'; + const SF_COUNTRY_NAME = 'CountryName__c'; + + /** + * Query fields available in SF for a BongCity + */ + const SF_FIELD_LIST = [ + self::SF_ID, + self::SF_NAME, + self::SF_ID_BONG, + self::SF_COUNTRY_NAME, + ]; +} \ No newline at end of file diff --git a/src/Types/City.php b/src/Types/City.php new file mode 100644 index 0000000..0757394 --- /dev/null +++ b/src/Types/City.php @@ -0,0 +1,28 @@ + + */ +class City +{ + const SF_OBJECT = 'City__c'; + + const SF_ID = 'Id'; + const SF_NAME = 'Name'; + const SF_COUNTRY = 'Country__c'; + const SF_COUNTRY_NAME = 'Country__r.Name'; + + /** + * Query fields available in SF for a City + */ + const SF_FIELD_LIST = [ + self::SF_ID, + self::SF_NAME, + self::SF_COUNTRY, + ]; +} \ No newline at end of file diff --git a/src/Types/Contact.php b/src/Types/Contact.php new file mode 100644 index 0000000..4f4e1ab --- /dev/null +++ b/src/Types/Contact.php @@ -0,0 +1,33 @@ + + */ +class Contact +{ + const SF_OBJECT = 'Contact'; + + const SF_ID = 'Id'; + const SF_TITLE = 'Title'; + const SF_FIRST_NAME = 'FirstName'; + const SF_LAST_NAME = 'LastName'; + const SF_EMAIL = 'Email'; + const SF_PHONE = 'Phone'; + + /** + * Query fields available in SF for a Contact + */ + const SF_FIELD_LIST = [ + self::SF_ID, + self::SF_TITLE, + self::SF_FIRST_NAME, + self::SF_LAST_NAME, + self::SF_EMAIL, + self::SF_PHONE + ]; +} \ No newline at end of file diff --git a/src/Types/ContactRelationshipAccount.php b/src/Types/ContactRelationshipAccount.php new file mode 100644 index 0000000..2c97d2c --- /dev/null +++ b/src/Types/ContactRelationshipAccount.php @@ -0,0 +1,35 @@ + + */ +class ContactRelationshipAccount +{ + const SF_OBJECT = 'Account_Contact_Relationship__c'; + + const SF_ID = 'Id'; + const SF_ACCOUNT = 'Account__c'; + const SF_ACCOUNT_ID = 'Account__r.Id'; + const SF_NAME = 'Name'; + const SF_CONTACT = 'Contact__c'; + const SF_ROLE = 'Contact_Roles__c'; + const SF_LONG_NAME = 'Relation_Name__c'; + const SF_EMAIL = 'Contact__r.Email'; + + /** + * Query fields available in SF for a Contact + */ + const SF_FIELD_LIST = [ + self::SF_ID, + self::SF_ACCOUNT, + self::SF_NAME, + self::SF_CONTACT, + self::SF_ROLE + ]; +} \ No newline at end of file diff --git a/src/Types/ContactRelationshipProduct.php b/src/Types/ContactRelationshipProduct.php new file mode 100644 index 0000000..2d6826e --- /dev/null +++ b/src/Types/ContactRelationshipProduct.php @@ -0,0 +1,35 @@ + + */ +class ContactRelationshipProduct +{ + const SF_OBJECT = 'ProductVP_Contact_Relationship__c'; + + const SF_ID = 'Id'; + const SF_PRODUCT = 'Product_VP__c'; + const SF_NAME = 'Relation_Name__c'; + const SF_CONTACT = 'Contact__c'; + const SF_CONTACT_EMAIL = 'Contact__r.Email'; + const SF_ROLE = 'Contact_Roles__c'; + const SF_LONG_NAME = 'Relation_Name__c'; + + /** + * Query fields available in SF for a Contact + */ + const SF_FIELD_LIST = [ + self::SF_ID, + self::SF_PRODUCT, + self::SF_NAME, + self::SF_CONTACT, + self::SF_CONTACT_EMAIL, + self::SF_ROLE + ]; +} \ No newline at end of file diff --git a/src/Types/Country.php b/src/Types/Country.php new file mode 100644 index 0000000..395806b --- /dev/null +++ b/src/Types/Country.php @@ -0,0 +1,25 @@ + + */ +class Country +{ + const SF_OBJECT = 'Country__c'; + + const SF_ID = 'Id'; + const SF_NAME = 'Name'; + + /** + * Query fields available in SF for a City + */ + const SF_FIELD_LIST = [ + self::SF_ID, + self::SF_NAME, + ]; +} \ No newline at end of file diff --git a/src/Types/Product.php b/src/Types/Product.php new file mode 100644 index 0000000..cec5b2e --- /dev/null +++ b/src/Types/Product.php @@ -0,0 +1,61 @@ + + */ +class Product +{ + const SF_OBJECT = 'Product__c'; + + const SF_ID = 'Id'; + const SF_NAME = 'Name'; + const SF_COUNTRY = 'Product_Country__c'; + const SF_CITY = 'Product_City__c'; + const SF_STREET = 'Product_Street__c'; + const SF_ZIPCODE = 'Product_Zip_Postal_code__c'; + const SF_STATUS = 'Validation_Status__c'; + const SF_RECORD_TYPE = 'RecordTypeId'; + const SF_CAPACITY = 'Capacity__c'; + const SF_TYPE = 'RecordTypeId'; + const SF_FRONT_EMAIL = 'Front_Desk_Email__c'; + const SF_FRONT_PHONE = 'Front_Desk_Phone__c'; + const SF_COORDINATE = 'GPS_coordinates__c'; + const SF_CATEGORY = 'Category__c'; + const SF_ATH_ID = 'Product_ATH_id__c'; + const SF_GPS_LAT = 'GPS_coordinates__Latitude__s'; + const SF_GPS_LNG = 'GPS_coordinates__Longitude__s'; + const SF_ACCOUNT = 'Account__c'; + const SF_BOOKING_URL = 'Booking_or_Trip__c'; + const SF_TRIPADVISOR_URL = 'Tripadvisor_link__c'; + const SF_BOOKING_SCORE = 'Market_Score__c'; + const SF_TRIPDVISOR_SCORE = 'Market_Score_TripAdvisor__c'; + const SF_ROOMING_LIST_CONTACT = 'Number_of_Rooming_List_Contact__c'; + + const SF_PENDING_STATUS = 'Pending'; + const SF_ACTIVE_STATUS = 'Approved'; + const SF_INACTIVE_STATUS = 'Refused'; + + /** + * Query fields available in SF for a Product + */ + const SF_FIELD_LIST = [ + self::SF_ID, + self::SF_NAME, + self::SF_COUNTRY, + self::SF_CITY, + self::SF_STREET, + self::SF_ZIPCODE, + self::SF_STATUS, + self::SF_CAPACITY, + self::SF_TYPE, + self::SF_FRONT_EMAIL, + self::SF_FRONT_PHONE, + self::SF_COORDINATE, + self::SF_CATEGORY + ]; +} \ No newline at end of file