diff --git a/Tests/AuthProvider/LoginAuthProviderTest.php b/Tests/AuthProvider/LoginAuthProviderTest.php index b58ec19..058f504 100644 --- a/Tests/AuthProvider/LoginAuthProviderTest.php +++ b/Tests/AuthProvider/LoginAuthProviderTest.php @@ -8,14 +8,14 @@ namespace AE\SalesforceRestSdk\Tests\AuthProvider; -use AE\SalesforceRestSdk\AuthProvider\LoginProvider; +use AE\SalesforceRestSdk\AuthProvider\OAuthProvider; use PHPUnit\Framework\TestCase; class LoginAuthProviderTest extends TestCase { public function testReauthorize() { - $auth = new LoginProvider( + $auth = new OAuthProvider( getenv("SF_CLIENT_ID"), getenv("SF_CLIENT_SECRET"), getenv("SF_USER"), @@ -23,7 +23,7 @@ public function testReauthorize() getenv("SF_LOGIN_URL") ); - $class = new \ReflectionClass(LoginProvider::class); + $class = new \ReflectionClass(OAuthProvider::class); $tokenProperty = $class->getProperty('token'); $tokenProperty->setAccessible(true); diff --git a/Tests/AuthProvider/SoapAuthProviderTest.php b/Tests/AuthProvider/SoapAuthProviderTest.php new file mode 100644 index 0000000..e6de624 --- /dev/null +++ b/Tests/AuthProvider/SoapAuthProviderTest.php @@ -0,0 +1,43 @@ +authorize(); + + $this->assertNotNull($header); + $this->assertNotNull($auth->getToken()); + $this->assertNotNull($auth->getInstanceUrl()); + + $class = new \ReflectionClass(SoapProvider::class); + + $tokenProperty = $class->getProperty('token'); + $tokenProperty->setAccessible(true); + $tokenProperty->setValue($auth, 'BAD_VALUE'); + + $header = $auth->reauthorize(); + + $this->assertNotNull($header); + $this->assertNotNull($auth->getToken()); + $this->assertNotNull($auth->getInstanceUrl()); + $this->assertEquals('Bearer', $auth->getTokenType()); + } +} diff --git a/Tests/Bayeux/BayeuxClientTest.php b/Tests/Bayeux/BayeuxClientTest.php index a4766f8..6e45cfa 100644 --- a/Tests/Bayeux/BayeuxClientTest.php +++ b/Tests/Bayeux/BayeuxClientTest.php @@ -8,7 +8,7 @@ namespace AE\SalesforceRestSdk\Tests\Bayeux; -use AE\SalesforceRestSdk\AuthProvider\LoginProvider; +use AE\SalesforceRestSdk\AuthProvider\OAuthProvider; use AE\SalesforceRestSdk\Bayeux\BayeuxClient; use AE\SalesforceRestSdk\Bayeux\ChannelInterface; use AE\SalesforceRestSdk\Bayeux\Consumer; @@ -31,7 +31,7 @@ protected function setUp() { $this->client = new BayeuxClient( new LongPollingTransport(), - new LoginProvider( + new OAuthProvider( getenv("SF_CLIENT_ID"), getenv("SF_CLIENT_SECRET"), getenv("SF_USER"), @@ -112,7 +112,7 @@ public function testHandshakeReauth() $this->client->disconnect(); } - $class = new \ReflectionClass(LoginProvider::class); + $class = new \ReflectionClass(OAuthProvider::class); $tokenProperty = $class->getProperty('token'); $tokenProperty->setAccessible(true); diff --git a/Tests/Bulk/BulkClientTest.php b/Tests/Bulk/BulkClientTest.php index a130e3b..d1a8f67 100644 --- a/Tests/Bulk/BulkClientTest.php +++ b/Tests/Bulk/BulkClientTest.php @@ -8,7 +8,7 @@ namespace AE\SalesforceRestSdk\Tests\Bulk; -use AE\SalesforceRestSdk\AuthProvider\LoginProvider; +use AE\SalesforceRestSdk\AuthProvider\OAuthProvider; use AE\SalesforceRestSdk\Bulk\BatchInfo; use AE\SalesforceRestSdk\Bulk\Client; use AE\SalesforceRestSdk\Bulk\JobInfo; @@ -39,7 +39,7 @@ class BulkClientTest extends TestCase protected function setUp()/* The :void return type declaration that should be here would cause a BC issue */ { $this->client = new Client( - new LoginProvider( + new OAuthProvider( getenv("SF_CLIENT_ID"), getenv("SF_CLIENT_SECRET"), getenv("SF_USER"), diff --git a/Tests/Rest/ClientTest.php b/Tests/Rest/ClientTest.php index 0652240..cbf799f 100644 --- a/Tests/Rest/ClientTest.php +++ b/Tests/Rest/ClientTest.php @@ -7,7 +7,7 @@ */ namespace AE\SalesforceRestSdk\Tests\Rest; -use AE\SalesforceRestSdk\AuthProvider\LoginProvider; +use AE\SalesforceRestSdk\AuthProvider\OAuthProvider; use AE\SalesforceRestSdk\Rest\Client; use PHPUnit\Framework\TestCase; @@ -21,7 +21,7 @@ class ClientTest extends TestCase protected function setUp()/* The :void return type declaration that should be here would cause a BC issue */ { $this->client = new Client( - new LoginProvider( + new OAuthProvider( getenv("SF_CLIENT_ID"), getenv("SF_CLIENT_SECRET"), getenv("SF_USER"), @@ -46,7 +46,7 @@ public function testRetry() $this->assertNotNull($limits); - $class = new \ReflectionClass(LoginProvider::class); + $class = new \ReflectionClass(OAuthProvider::class); $tokenProperty = $class->getProperty('token'); $tokenProperty->setAccessible(true); diff --git a/Tests/Rest/Composite/CompositeClientTest.php b/Tests/Rest/Composite/CompositeClientTest.php index a236aed..825ef33 100644 --- a/Tests/Rest/Composite/CompositeClientTest.php +++ b/Tests/Rest/Composite/CompositeClientTest.php @@ -8,7 +8,7 @@ namespace AE\SalesforceRestSdk\Tests\Composite; -use AE\SalesforceRestSdk\AuthProvider\LoginProvider; +use AE\SalesforceRestSdk\AuthProvider\OAuthProvider; use AE\SalesforceRestSdk\Model\Rest\Composite\CollectionResponse; use AE\SalesforceRestSdk\Model\Rest\Composite\CompositeCollection; use AE\SalesforceRestSdk\Model\Rest\Composite\CompositeSObject; @@ -30,7 +30,7 @@ class CompositeClientTest extends TestCase protected function setUp() { $client = new Client( - new LoginProvider( + new OAuthProvider( getenv("SF_CLIENT_ID"), getenv("SF_CLIENT_SECRET"), getenv("SF_USER"), diff --git a/Tests/Rest/SObject/SObjectClientTest.php b/Tests/Rest/SObject/SObjectClientTest.php index 7365010..41b56a7 100644 --- a/Tests/Rest/SObject/SObjectClientTest.php +++ b/Tests/Rest/SObject/SObjectClientTest.php @@ -8,7 +8,7 @@ namespace AE\SalesforceRestSdk\Tests\Rest\SObject; -use AE\SalesforceRestSdk\AuthProvider\LoginProvider; +use AE\SalesforceRestSdk\AuthProvider\OAuthProvider; use AE\SalesforceRestSdk\Model\SObject; use AE\SalesforceRestSdk\Rest\SObject\Client; use PHPUnit\Framework\TestCase; @@ -24,7 +24,7 @@ class SObjectClientTest extends TestCase protected function setUp()/* The :void return type declaration that should be here would cause a BC issue */ { $client = new \AE\SalesforceRestSdk\Rest\Client( - new LoginProvider( + new OAuthProvider( getenv("SF_CLIENT_ID"), getenv("SF_CLIENT_SECRET"), getenv("SF_USER"), diff --git a/src/AuthProvider/LoginProvider.php b/src/AuthProvider/LoginProvider.php index 39d256b..97281a0 100644 --- a/src/AuthProvider/LoginProvider.php +++ b/src/AuthProvider/LoginProvider.php @@ -2,165 +2,19 @@ /** * Created by PhpStorm. * User: alex.boyce - * Date: 9/6/18 - * Time: 3:27 PM + * Date: 10/23/18 + * Time: 9:07 AM */ namespace AE\SalesforceRestSdk\AuthProvider; -use GuzzleHttp\Client; - -class LoginProvider implements AuthProviderInterface +/** + * Class LoginProvider + * + * @package AE\SalesforceRestSdk\AuthProvider + * @deprecated To be removed in a later version + */ +class LoginProvider extends OAuthProvider { - /** - * @var bool - */ - private $isAuthorized = false; - - /** - * @var string - */ - private $token; - - /** - * @var string - */ - private $tokenType; - - /** - * @var Client - */ - private $httpClient; - - /** - * @var string - */ - private $username; - - /** - * @var string - */ - private $password; - - /** - * @var string - */ - private $clientId; - - /** - * @var string - */ - private $clientSecret; - - /** - * @var null|string - */ - private $instanceUrl; - - public function __construct(string $clientId, string $clientSecret, string $username, string $password, string $url) - { - $this->clientId = $clientId; - $this->clientSecret = $clientSecret; - $this->username = $username; - $this->password = $password; - - $this->httpClient = new Client( - [ - 'base_uri' => $url, - ] - ); - } - - /** - * @param bool $reauth - * - * @throws SessionExpiredOrInvalidException - * @return string - */ - public function authorize($reauth = false): string - { - if (!$reauth && $this->isAuthorized && strlen($this->token) > 0) { - return "{$this->tokenType} {$this->token}"; - } - - $response = $this->httpClient->post( - '/services/oauth2/token', - [ - 'form_params' => [ - 'grant_type' => 'password', - 'client_id' => $this->clientId, - 'client_secret' => $this->clientSecret, - 'username' => $this->username, - 'password' => $this->password, - ], - 'headers' => [ - 'Content-Type' => 'application/x-www-form-urlencoded', - 'Accept' => 'application/json', - ], - ] - ); - - $body = (string)$response->getBody(); - $parts = json_decode($body, true); - - if (401 === $response->getStatusCode()) { - throw new SessionExpiredOrInvalidException($parts['message'], $parts['errorCode']); - } - - $this->tokenType = $parts['token_type']; - $this->token = $parts['access_token']; - $this->instanceUrl = $parts['instance_url']; - - $this->isAuthorized = true; - - return "{$this->tokenType} {$this->token}"; - } - - /** - * @return string - */ - public function reauthorize(): string - { - return $this->authorize(true); - } - - - public function revoke(): void - { - $this->token = null; - $this->tokenType = null; - $this->isAuthorized = false; - } - - /** - * @return string - */ - public function getToken(): ?string - { - return $this->token; - } - - /** - * @return string - */ - public function getTokenType(): ?string - { - return $this->tokenType; - } - - /** - * @return bool - */ - public function isAuthorized(): bool - { - return $this->isAuthorized; - } - /** - * @return null|string - */ - public function getInstanceUrl(): ?string - { - return $this->instanceUrl; - } } diff --git a/src/AuthProvider/OAuthProvider.php b/src/AuthProvider/OAuthProvider.php new file mode 100644 index 0000000..a71a3d2 --- /dev/null +++ b/src/AuthProvider/OAuthProvider.php @@ -0,0 +1,166 @@ +clientId = $clientId; + $this->clientSecret = $clientSecret; + $this->username = $username; + $this->password = $password; + + $this->httpClient = new Client( + [ + 'base_uri' => $url, + ] + ); + } + + /** + * @param bool $reauth + * + * @throws SessionExpiredOrInvalidException + * @return string + */ + public function authorize($reauth = false): string + { + if (!$reauth && $this->isAuthorized && strlen($this->token) > 0) { + return "{$this->tokenType} {$this->token}"; + } + + $response = $this->httpClient->post( + '/services/oauth2/token', + [ + 'form_params' => [ + 'grant_type' => 'password', + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + 'username' => $this->username, + 'password' => $this->password, + ], + 'headers' => [ + 'Content-Type' => 'application/x-www-form-urlencoded', + 'Accept' => 'application/json', + ], + ] + ); + + $body = (string)$response->getBody(); + $parts = json_decode($body, true); + + if (401 === $response->getStatusCode()) { + throw new SessionExpiredOrInvalidException($parts['message'], $parts['errorCode']); + } + + $this->tokenType = $parts['token_type']; + $this->token = $parts['access_token']; + $this->instanceUrl = $parts['instance_url']; + + $this->isAuthorized = true; + + return "{$this->tokenType} {$this->token}"; + } + + /** + * @return string + */ + public function reauthorize(): string + { + return $this->authorize(true); + } + + + public function revoke(): void + { + $this->token = null; + $this->tokenType = null; + $this->isAuthorized = false; + } + + /** + * @return string + */ + public function getToken(): ?string + { + return $this->token; + } + + /** + * @return string + */ + public function getTokenType(): ?string + { + return $this->tokenType; + } + + /** + * @return bool + */ + public function isAuthorized(): bool + { + return $this->isAuthorized; + } + + /** + * @return null|string + */ + public function getInstanceUrl(): ?string + { + return $this->instanceUrl; + } +} diff --git a/src/AuthProvider/SoapProvider.php b/src/AuthProvider/SoapProvider.php new file mode 100644 index 0000000..7d16f15 --- /dev/null +++ b/src/AuthProvider/SoapProvider.php @@ -0,0 +1,158 @@ +username = $username; + $this->password = $password; + $this->httpClient = new Client( + [ + 'base_uri' => $url, + 'headers' => [ + 'Content-Type' => 'text/xml', + 'SOAPAction' => '""', + ], + ] + ); + } + + public function authorize($reauth = false) + { + if (!$reauth && $this->isAuthorized && strlen($this->token) > 0) { + return "{$this->tokenType} {$this->token}"; + } + + $body + = " + + + {$this->username} + {$this->password} + + +"; + + try { + $response = $this->httpClient->post( + '/services/Soap/u/'.self::VERSION, + [ + 'body' => $body, + ] + ); + + $soapBody = (string)$response->getBody(); + + $matches = []; + if (false != preg_match( + '/(?.*?)<\/serverUrl>.*?(?.*?)<\/sessionId>/', + $soapBody, + $matches + )) { + $this->instanceUrl = $matches['serverUrl']; + $this->token = $matches['sessionId']; + } else { + throw new SessionExpiredOrInvalidException("Failed to login to Salesforce.", "INVALID_CREDENTIALS"); + } + + return "{$this->tokenType} {$this->token}"; + } catch (RequestException $e) { + $response = $e->getResponse(); + $body = (string) $response->getBody(); + throw new SessionExpiredOrInvalidException( + "Failed to authenticate with Salesforce.", + "INVALID_CREDENTIALS" + ); + } + } + + public function reauthorize() + { + return $this->authorize(true); + } + + public function revoke(): void + { + $this->token = null; + $this->isAuthorized = false; + } + + /** + * @return string + */ + public function getToken(): ?string + { + return $this->token; + } + + /** + * @return string + */ + public function getTokenType(): ?string + { + return $this->tokenType; + } + + /** + * @return bool + */ + public function isAuthorized(): bool + { + return $this->isAuthorized; + } + + /** + * @return null|string + */ + public function getInstanceUrl(): ?string + { + return $this->instanceUrl; + } +} diff --git a/src/Bulk/Client.php b/src/Bulk/Client.php index 10f4c68..44db76b 100644 --- a/src/Bulk/Client.php +++ b/src/Bulk/Client.php @@ -29,7 +29,7 @@ class Client extends AbstractClient /** * */ - public const VERSION = "43.0"; + public const VERSION = "44.0"; /** * diff --git a/src/Model/Rest/Composite/CollectionRequest.php b/src/Model/Rest/Composite/CollectionRequest.php index 628f4ed..c475dc5 100644 --- a/src/Model/Rest/Composite/CollectionRequest.php +++ b/src/Model/Rest/Composite/CollectionRequest.php @@ -29,7 +29,7 @@ class CollectionRequest implements CollectionRequestInterface /** * @var Collection - * @Serializer\Type("ArrayCollection") + * @Serializer\Type("ArrayCollection") */ private $records; diff --git a/src/Model/Rest/Composite/SObject/GetDeletedSubRequest.php b/src/Model/Rest/Composite/SObject/GetDeletedSubRequest.php index eaa2313..23c151e 100644 --- a/src/Model/Rest/Composite/SObject/GetDeletedSubRequest.php +++ b/src/Model/Rest/Composite/SObject/GetDeletedSubRequest.php @@ -117,9 +117,12 @@ public function preSerialize() $this->url = '/'.Client::BASE_PATH.'sobjects/'.$this->sObjectType.'/deleted/?' .http_build_query( [ - 'start' => $this->start->format(\DATE_ISO8601), - 'end' => $this->end->format(\DATE_ISO8601), - ] + 'start' => $this->start->format('Y-m-d\Th:i:sP'), + 'end' => $this->end->format('Y-m-d\Th:i:sP'), + ], + null, + '&', + PHP_QUERY_RFC3986 ); } } diff --git a/src/Model/Rest/Composite/SObject/GetUpdatedSubRequest.php b/src/Model/Rest/Composite/SObject/GetUpdatedSubRequest.php index e622f6e..0755277 100644 --- a/src/Model/Rest/Composite/SObject/GetUpdatedSubRequest.php +++ b/src/Model/Rest/Composite/SObject/GetUpdatedSubRequest.php @@ -113,9 +113,12 @@ public function preSerialize() $this->url = '/'.Client::BASE_PATH.'sobjects/'.$this->sObjectType.'/updated/?' .http_build_query( [ - 'start' => $this->start->format(\DATE_ISO8601), - 'end' => $this->end->format(\DATE_ISO8601), - ] + 'start' => $this->start->format('Y-m-d\Th:i:sP'), + 'end' => $this->end->format('Y-m-d\Th:i:sP'), + ], + null, + '&', + PHP_QUERY_RFC3986 ); } } diff --git a/src/Model/Rest/DeletedResponse.php b/src/Model/Rest/DeletedResponse.php index cc2517b..258d4ef 100644 --- a/src/Model/Rest/DeletedResponse.php +++ b/src/Model/Rest/DeletedResponse.php @@ -8,7 +8,6 @@ namespace AE\SalesforceRestSdk\Model\Rest; -use AE\SalesforceRestSdk\Model\SObject; use JMS\Serializer\Annotation as Serializer; /** @@ -20,7 +19,7 @@ class DeletedResponse { /** - * @var array|SObject[] + * @var array|DeletedRecord[] * @Serializer\Type("array") */ private $deletedRecords = []; @@ -38,7 +37,7 @@ class DeletedResponse private $latestDateCovered; /** - * @return SObject[]|array + * @return DeletedRecord[]|array */ public function getDeletedRecords() { @@ -46,7 +45,7 @@ public function getDeletedRecords() } /** - * @param SObject[]|array $deletedRecords + * @param DeletedRecord[]|array $deletedRecords * * @return DeletedResponse */ @@ -58,7 +57,7 @@ public function setDeletedRecords($deletedRecords) } /** - * @return \DateTime|null + * @return \DateTime|\DateTimeImmutable|null */ public function getEarliestDateAvailable(): ?\DateTime { diff --git a/src/Rest/Client.php b/src/Rest/Client.php index 50c0147..16643d5 100644 --- a/src/Rest/Client.php +++ b/src/Rest/Client.php @@ -26,7 +26,7 @@ class Client extends AbstractClient { - public const VERSION = "43.0"; + public const VERSION = "44.0"; /** * @var string diff --git a/src/Rest/Composite/Builder/ArrayReference.php b/src/Rest/Composite/Builder/ArrayReference.php index da8a234..9c13050 100644 --- a/src/Rest/Composite/Builder/ArrayReference.php +++ b/src/Rest/Composite/Builder/ArrayReference.php @@ -12,6 +12,6 @@ class ArrayReference extends Reference { public function field(string $field, int $index = 0) { - return "@{{$this->getReferenceId()}[$index].$field}"; + return "@{{$this->getReferenceId()}.[$index].$field}"; } } diff --git a/src/Rest/Composite/Builder/CompositeRequestBuilder.php b/src/Rest/Composite/Builder/CompositeRequestBuilder.php index fa425df..829398a 100644 --- a/src/Rest/Composite/Builder/CompositeRequestBuilder.php +++ b/src/Rest/Composite/Builder/CompositeRequestBuilder.php @@ -117,7 +117,7 @@ public function getDeleted( string $referenceId, string $sObjectType, \DateTime $start, - ?\DateTime $end + ?\DateTime $end = null ): CompositeRequestBuilder { return $this->addSubRequest( new GetDeletedSubRequest( diff --git a/src/Rest/Composite/CompositeClient.php b/src/Rest/Composite/CompositeClient.php index f89d700..304d3ee 100644 --- a/src/Rest/Composite/CompositeClient.php +++ b/src/Rest/Composite/CompositeClient.php @@ -24,7 +24,7 @@ class CompositeClient extends AbstractClient { - public const VERSION = '43.0'; + public const VERSION = '44.0'; public const BASE_PATH = '/services/data/v'.self::VERSION.'/composite'; diff --git a/src/Rest/SObject/Client.php b/src/Rest/SObject/Client.php index d3eb82c..59068e8 100644 --- a/src/Rest/SObject/Client.php +++ b/src/Rest/SObject/Client.php @@ -25,7 +25,7 @@ class Client extends AbstractClient { - public const VERSION = "43.0"; + public const VERSION = "44.0"; public const BASE_PATH = "services/data/v".self::VERSION."/"; @@ -155,9 +155,12 @@ public function getUpdated(string $sObjectType, \DateTime $start, \DateTime $end self::BASE_PATH.'sobjects/'.$sObjectType.'/updated/?'. http_build_query( [ - 'start' => $start->format(\DateTime::ISO8601), - 'end' => $end->format(\DateTime::ISO8601), - ] + 'start' => $start->format('Y-m-d\Th:i:sP'), + 'end' => $end->format('Y-m-d\Th:i:sP'), + ], + null, + '&', + PHP_QUERY_RFC3986 ) ) ); @@ -195,9 +198,12 @@ public function getDeleted(string $sObjectType, \DateTime $start, \DateTime $end self::BASE_PATH.'sobjects/'.$sObjectType.'/deleted/?'. http_build_query( [ - 'start' => $start->format(\DateTime::ISO8601), - 'end' => $end->format(\DateTime::ISO8601), - ] + 'start' => $start->format('Y-m-d\Th:i:sP'), + 'end' => $end->format('Y-m-d\Th:i:sP'), + ], + null, + '&', + PHP_QUERY_RFC3986 ) ) );