Skip to content

Commit e549b03

Browse files
committed
Merge pull request #143 from bc-bfenton/oauth
Reimplementing PR 88 with corrections for underlying code drift
2 parents 15c1d16 + 7a68f07 commit e549b03

2 files changed

Lines changed: 133 additions & 11 deletions

File tree

src/Bigcommerce/Api/Client.php

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,58 @@ class Client
5757
* @var string
5858
*/
5959
static public $api_path;
60+
static private $client_id;
61+
static private $store_hash;
62+
static private $auth_token;
63+
static private $stores_prefix = '/stores/%s/v2';
64+
static private $api_url = 'https://api.bigcommerce.com';
65+
static private $login_url = 'https://login.bigcommerce.com';
66+
67+
/**
68+
* Configure the API client with the required settings to access
69+
* the API for a store.
70+
*
71+
* Accepts OAuth and (for now!) Basic Auth credentials
72+
*
73+
* @param array $settings
74+
*/
75+
public static function configure($settings)
76+
{
77+
if (isset($settings['client_id'])) {
78+
self::configureOAuth($settings);
79+
} else {
80+
self::configureBasicAuth($settings);
81+
}
82+
}
83+
84+
/**
85+
* Configure the API client with the required OAuth credentials.
86+
*
87+
* Requires a settings array to be passed in with the following keys:
88+
*
89+
* - client_id
90+
* - auth_token
91+
* - store_hash
92+
*
93+
* @param array $settings
94+
* @throws \Exception
95+
*/
96+
public static function configureOAuth($settings)
97+
{
98+
if (!isset($settings['auth_token'])) {
99+
throw new Exception("'auth_token' must be provided");
100+
}
101+
102+
if (!isset($settings['store_hash'])) {
103+
throw new Exception("'store_hash' must be provided");
104+
}
105+
106+
self::$client_id = $settings['client_id'];
107+
self::$auth_token = $settings['auth_token'];
108+
self::$store_hash = $settings['store_hash'];
109+
self::$api_path = self::$api_url . sprintf(self::$stores_prefix, self::$store_hash);
110+
self::$connection = false;
111+
}
60112

61113
/**
62114
* Configure the API client with the required credentials.
@@ -70,7 +122,7 @@ class Client
70122
* @param array $settings
71123
* @throws \Exception
72124
*/
73-
public static function configure(array $settings)
125+
public static function configureBasicAuth(array $settings)
74126
{
75127
if (!isset($settings['store_url'])) {
76128
throw new Exception("'store_url' must be provided");
@@ -162,7 +214,11 @@ private static function connection()
162214
{
163215
if (!self::$connection) {
164216
self::$connection = new Connection();
165-
self::$connection->authenticate(self::$username, self::$api_key);
217+
if (self::$client_id) {
218+
self::$connection->authenticateOauth(self::$client_id, self::$auth_token);
219+
} else {
220+
self::$connection->authenticateBasic(self::$username, self::$api_key);
221+
}
166222
}
167223

168224
return self::$connection;
@@ -342,6 +398,21 @@ private static function mapCount($object)
342398
return $object->count;
343399
}
344400

401+
/**
402+
* Swaps a temporary access code for a long expiry auth token.
403+
*
404+
* @param \stdClass $object
405+
* @return \stdClass
406+
*/
407+
public static function getAuthToken($object)
408+
{
409+
$context = array_merge(array('grant_type' => 'authorization_code'), (array)$object);
410+
$connection = new Connection();
411+
$connection->useUrlEncoded();
412+
413+
return $connection->post(self::$login_url . '/oauth2/token', $context);
414+
}
415+
345416
/**
346417
* Pings the time endpoint to test the connection to a store.
347418
*

src/Bigcommerce/Api/Connection.php

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@
77
*/
88
class Connection
99
{
10+
/**
11+
* XML media type.
12+
*/
13+
const MEDIA_TYPE_XML = 'application/xml';
14+
/**
15+
* JSON media type.
16+
*/
17+
const MEDIA_TYPE_JSON = 'application/json';
18+
/**
19+
* Default urlencoded media type.
20+
*/
21+
const MEDIA_TYPE_WWW = 'application/x-www-form-urlencoded';
1022

1123
/**
1224
* @var resource cURL resource
@@ -60,15 +72,19 @@ class Connection
6072

6173
/**
6274
* Deal with failed requests if failOnError is not set.
63-
* @var string | false
75+
* @var string|false
6476
*/
6577
private $lastError = false;
6678

6779
/**
68-
* Determines whether requests and responses should be treated
69-
* as XML. Defaults to false (using JSON).
80+
* Determines whether the response body should be returned as a raw string.
7081
*/
71-
private $useXml = false;
82+
private $rawResponse = false;
83+
84+
/**
85+
* Determines the default content type to use with requests and responses.
86+
*/
87+
private $contentType;
7288

7389
/**
7490
* Initializes the connection object.
@@ -96,7 +112,23 @@ public function __construct()
96112
*/
97113
public function useXml($option = true)
98114
{
99-
$this->useXml = $option;
115+
if ($option) {
116+
$this->contentType = self::MEDIA_TYPE_XML;
117+
$this->rawResponse = true;
118+
}
119+
}
120+
121+
/**
122+
* Controls whether requests or responses should be treated
123+
* as urlencoded form data.
124+
*
125+
* @param bool $option the new state of this feature
126+
*/
127+
public function useUrlEncoded($option = true)
128+
{
129+
if ($option) {
130+
$this->contentType = self::MEDIA_TYPE_WWW;
131+
}
100132
}
101133

102134
/**
@@ -125,11 +157,23 @@ public function failOnError($option = true)
125157
* @param string $username
126158
* @param string $password
127159
*/
128-
public function authenticate($username, $password)
160+
public function authenticateBasic($username, $password)
129161
{
130162
curl_setopt($this->curl, CURLOPT_USERPWD, "$username:$password");
131163
}
132164

165+
/**
166+
* Sets Oauth authentication headers
167+
*
168+
* @param string $clientId
169+
* @param string $authToken
170+
*/
171+
public function authenticateOauth($clientId, $authToken)
172+
{
173+
$this->addHeader('X-Auth-Client', $clientId);
174+
$this->addHeader('X-Auth-Token', $authToken);
175+
}
176+
133177
/**
134178
* Set a default timeout for the request. The client will error if the
135179
* request takes longer than this to respond.
@@ -168,6 +212,9 @@ public function verifyPeer($option = false)
168212

169213
/**
170214
* Add a custom header to the request.
215+
*
216+
* @param string $header
217+
* @param string $value
171218
*/
172219
public function addHeader($header, $value)
173220
{
@@ -176,6 +223,7 @@ public function addHeader($header, $value)
176223

177224
/**
178225
* Remove a header from the request.
226+
*
179227
* @param string $header
180228
*/
181229
public function removeHeader($header)
@@ -185,10 +233,12 @@ public function removeHeader($header)
185233

186234
/**
187235
* Get the MIME type that should be used for this request.
236+
*
237+
* Defaults to application/json
188238
*/
189239
private function getContentType()
190240
{
191-
return ($this->useXml) ? 'application/xml' : 'application/json';
241+
return ($this->contentType) ? $this->contentType : self::MEDIA_TYPE_JSON;
192242
}
193243

194244
/**
@@ -197,7 +247,6 @@ private function getContentType()
197247
*/
198248
private function initializeRequest()
199249
{
200-
$this->isComplete = false;
201250
$this->responseBody = '';
202251
$this->responseHeaders = array();
203252
$this->lastError = false;
@@ -222,7 +271,7 @@ private function handleResponse()
222271
throw new NetworkError(curl_error($this->curl), curl_errno($this->curl));
223272
}
224273

225-
$body = ($this->useXml) ? $this->getBody() : json_decode($this->getBody());
274+
$body = ($this->rawResponse) ? $this->getBody() : json_decode($this->getBody());
226275

227276
$status = $this->getStatus();
228277

@@ -481,6 +530,8 @@ public function getBody()
481530
/**
482531
* Access given header from the response.
483532
*
533+
* @param string $header Header name to retrieve
534+
*
484535
* @return string|void
485536
*/
486537
public function getHeader($header)

0 commit comments

Comments
 (0)