diff options
author | Avi Goldman <avrahamymgoldman@gmail.com> | 2016-06-20 11:26:43 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-06-20 11:26:43 -0400 |
commit | 87552cc2766f4ea8c8a2d6ff6c70dd74faecb687 (patch) | |
tree | 0d37219ce699bffd8adc0cd5fb7c5ec012c80df0 /lib | |
parent | a5847be109dc6350fb0bc8beb8d0ba8bc23b75b6 (diff) | |
download | php-sparkpost-87552cc2766f4ea8c8a2d6ff6c70dd74faecb687.zip php-sparkpost-87552cc2766f4ea8c8a2d6ff6c70dd74faecb687.tar.gz php-sparkpost-87552cc2766f4ea8c8a2d6ff6c70dd74faecb687.tar.bz2 |
Merged FAD-3148 into 2.x
* FAD-3148 basic non-functioning base class
* FAD-3148 a bit more functionality in the base class
* FAD-3148 added custom promise class and custom response class. Did good things to SparkPost class
* Updated Transmission.php for new refactor, still WIP. Created Resource.php as a parent class for all future resources.
* Removed test functions
* Cleaned up Transmissions.php according to PSR-2, deleted more test code and comments.
* added sync and aysnc, cleaned up code
* added support for async/sync option
* added support for async/sync option
* Added interns to authors
* simplified the request function
* added comments
* added user agent
* added comments in SparkPostPromise
* added comments in SparkPostException
* added comments in SparkPostResponse
* cleaning up test
* updated composer.json and contributing files for testing
* Ran php-cs-fixer
* testing for sparkpost response class
* updated to newer version of guzzle
* updated to newer version of guzzle
* Cleaned up getUrl and other functions
* cleaned up constructor and overrode getCode with getResponse()->getStatusCode()
* fixed up then method
* cleaned up getBody
* deleted old test
* Wrote total coverage tests for SparkPost class
* commented out setting up transmissions endpoint until merging with FAD-3146
Diffstat (limited to 'lib')
-rw-r--r-- | lib/SendGridCompatibility/Email.php | 259 | ||||
-rw-r--r-- | lib/SendGridCompatibility/SendGrid.php | 26 | ||||
-rw-r--r-- | lib/SparkPost/APIResource.php | 265 | ||||
-rw-r--r-- | lib/SparkPost/APIResponseException.php | 62 | ||||
-rw-r--r-- | lib/SparkPost/MessageEvents.php | 64 | ||||
-rw-r--r-- | lib/SparkPost/SparkPost.php | 239 | ||||
-rw-r--r-- | lib/SparkPost/SparkPostException.php | 41 | ||||
-rw-r--r-- | lib/SparkPost/SparkPostPromise.php | 69 | ||||
-rw-r--r-- | lib/SparkPost/SparkPostResponse.php | 105 | ||||
-rw-r--r-- | lib/SparkPost/Transmission.php | 136 |
10 files changed, 378 insertions, 888 deletions
diff --git a/lib/SendGridCompatibility/Email.php b/lib/SendGridCompatibility/Email.php deleted file mode 100644 index 3ca2466..0000000 --- a/lib/SendGridCompatibility/Email.php +++ /dev/null @@ -1,259 +0,0 @@ -<?php - -namespace SparkPost\SendGridCompatibility; - -class Email -{ - public $model; - - /** - * Sets up the model for saving the configuration. - */ - public function __construct() - { - $this->model = array(); - } - - /** - * adds addresses as recipients. - * - * @param string $address - * @param string $name optional - * - * @return $this - */ - public function addTo($address, $name = null) - { - if (!isset($this->model['recipients'])) { - $this->model['recipients'] = array(); - } - - if (isset($name)) { - $address = array('address' => array('email' => $address, 'name' => $name)); - } else { - $address = array('address' => array('email' => $address)); - } - - array_push($this->model['recipients'], $address); - - return $this; - } - - /** - * explicitly sets a list of addresses. - * - * @param array $addresses - * - * @return $this - */ - public function setTos(array $addresses) - { - $this->model['recipients'] = $addresses; - - return $this; - } - - /** - * sets the from address. - * - * @param string $address - * - * @return $this - */ - public function setFrom($address) - { - $this->model['from'] = array('email' => $address); - - return $this; - } - - /** - * Sets the name for the from address. - * - * @param string $name - * - * @return $this - * - * @throws \Exception - */ - public function setFromName($name) - { - if (!isset($this->model['from'])) { - throw new \Exception('Must set \'From\' prior to setting \'From Name\'.'); - } - $this->model['from']['name'] = $name; - - return $this; - } - - /** - * sets the reply to field. - * - * @param string $address - * - * @return $this - */ - public function setReplyTo($address) - { - $this->model['replyTo'] = $address; - - return $this; - } - - /** - * throws an error because bcc fields are not yet implemented. - * - * @throws \Exception - * - * @param string $address - * - * @return $this - */ - public function addBcc($address) - { - throw new \Exception('Adding bcc recipients is not yet supported, try adding them as a \'to\' address'); - } - - /** - * sets the subject header. - * - * @param string $subject - * - * @return $this - */ - public function setSubject($subject) - { - $this->model['subject'] = $subject; - - return $this; - } - - /** - * sets the text body. - * - * @param string $text - * - * @return $this - */ - public function setText($text) - { - $this->model['text'] = $text; - - return $this; - } - - /** - * sets the html body. - * - * @param string $html - * - * @return $this - */ - public function setHtml($html) - { - $this->model['html'] = $html; - - return $this; - } - - /** - * Throws an exception since adding categories is not yet supported. - * - * @param string $category - * - * @throws \Exception - */ - public function addCategory($category) - { - throw new \Exception('Adding categories is not yet supported'); - } - - /** - * Throws an exception since adding attachments is not yet supported. - * - * @throws \Exception - * - * @param mixed $attachment - */ - public function addAttachment($attachment) - { - throw new \Exception('Adding attachments is not yet supported'); - } - - /** - * Adds transmission level substitution data. - * - * @param string $name - * @param mixed $values - * - * @return $this - */ - public function addSubstitution($name, $values) - { - if (!isset($this->model['substitutionData'])) { - $this->model['substitutionData'] = array(); - } - $this->model['substitutionData'][$name] = $values; - - return $this; - } - - /** - * Adds transmission level substitution data. - * - * @param string $name - * @param mixed $values - */ - public function addSection($name, $values) - { - $this->addSubstitution($name, $values); - } - - /** - * Throws an exception because arguments for third party systems is not supported. - * - * @throws \Exception - * - * @param mixed $value - */ - public function addUniqueArg($key, $value) - { - throw new \Exception('Adding Unique Arguments is not yet supported'); - } - - /** - * Throws an exception because arguments for third party systems is not supported. - * - * @throws \Exception - * - * @param mixed $values - */ - public function setUniqueArgs(array $values) - { - throw new \Exception('Setting Unique Arguments is not yet supported'); - } - - /** - * Adds custom headers to the email header. - * - * @param string $name - * @param string $value - */ - public function addHeader($name, $value) - { - if (!isset($this->model['customHeaders'])) { - $this->model['customHeaders'] = array(); - } - $this->model['customHeaders'][$name] = $value; - } - - /** - * converts this object to a configuration for a SparkPost transmission. - * - * @return array - */ - public function toSparkPostTransmission() - { - return $this->model; - } -} diff --git a/lib/SendGridCompatibility/SendGrid.php b/lib/SendGridCompatibility/SendGrid.php deleted file mode 100644 index c5e84c1..0000000 --- a/lib/SendGridCompatibility/SendGrid.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -namespace SparkPost\SendGridCompatibility; - -use SparkPost\SparkPost; - -class SendGrid -{ - private $sparky; - - public function __construct($username, $password, $options = null, $httpAdapter) - { - //username isn't used in our system - $opts = array('key' => $password); - if (!is_null($options)) { - $opts = array_merge($opts, $options); - } - - $this->sparky = new SparkPost($httpAdapter, $opts); - } - - public function send(Email $email) - { - $this->sparky->transmission->send($email->toSparkPostTransmission()); - } -} diff --git a/lib/SparkPost/APIResource.php b/lib/SparkPost/APIResource.php deleted file mode 100644 index 36b03a8..0000000 --- a/lib/SparkPost/APIResource.php +++ /dev/null @@ -1,265 +0,0 @@ -<?php - -namespace SparkPost; - -/** - * SDK interface for managing SparkPost API endpoints. - */ -class APIResource -{ - /** - * name of the API endpoint, mainly used for URL construction. - * This is public to provide an interface. - * - * @var string - */ - public $endpoint; - - /** - * Mapping for values passed into the send method to the values needed for the respective API. - * - * @var array - */ - protected static $parameterMappings = []; - - /** - * Sets up default structure and default values for the model that is acceptable by the API. - * - * @var array - */ - protected static $structure = []; - - /** - * SparkPost reference for httpAdapters and configs. - */ - protected $sparkpost; - - /** - * Initializes config and httpAdapter for use later. - * - * @param $sparkpost \SparkPost\SparkPost provides api configuration information - */ - public function __construct(SparkPost $sparkpost) - { - $this->sparkpost = $sparkpost; - } - - /** - * Private Method helper to reference parameter mappings and set the right value for the right parameter. - * - * @param array $model (pass by reference) the set of values to map - * @param string $mapKey a dot syntax path determining which value to set - * @param mixed $value value for the given path - */ - protected function setMappedValue(&$model, $mapKey, $value) - { - //get mapping - if (empty(static::$parameterMappings)) { - // if parameterMappings is empty we can assume that no wrapper is defined - // for the current endpoint and we will use the mapKey to define the mappings directly - $mapPath = $mapKey; - } elseif (array_key_exists($mapKey, static::$parameterMappings)) { - // use only defined parameter mappings to construct $model - $mapPath = static::$parameterMappings[$mapKey]; - } else { - return; - } - - $path = explode('.', $mapPath); - $temp = &$model; - foreach ($path as $key) { - if (!isset($temp[$key])) { - $temp[$key] = null; - } - $temp = &$temp[$key]; - } - $temp = $value; - } - - /** - * maps values from the passed in model to those needed for the request. - * - * @param array $requestConfig the passed in model - * @param array $model the set of defaults - * - * @return array A model ready for the body of a request - */ - protected function buildRequestModel(array $requestConfig, array $model = []) - { - foreach ($requestConfig as $key => $value) { - $this->setMappedValue($model, $key, $value); - } - - return $model; - } - - /** - * posts to the api with a supplied body. - * - * @param array $body post body for the request - * - * @return array Result of the request - */ - public function create(array $body = []) - { - return $this->callResource('post', null, ['body' => $body]); - } - - /** - * Makes a put request to the api with a supplied body. - * - * @param $resourcePath - * @param array $body Put body for the request - * - * @return array Result of the request - * - * @throws APIResponseException - */ - public function update($resourcePath, array $body = []) - { - return $this->callResource('put', $resourcePath, ['body' => $body]); - } - - /** - * Wrapper method for issuing GET request to current API endpoint. - * - * @param string $resourcePath (optional) string resource path of specific resource - * @param array $query (optional) query string parameters - * - * @return array Result of the request - */ - public function get($resourcePath = null, array $query = []) - { - return $this->callResource('get', $resourcePath, ['query' => $query]); - } - - /** - * Wrapper method for issuing DELETE request to current API endpoint. - * - * @param string $resourcePath (optional) string resource path of specific resource - * @param array $query (optional) query string parameters - * - * @return array Result of the request - */ - public function delete($resourcePath = null, array $query = []) - { - return $this->callResource('delete', $resourcePath, ['query' => $query]); - } - - /** - * assembles a URL for a request. - * - * @param string $resourcePath path after the initial endpoint - * @param array $options array with an optional value of query with values to build a querystring from. Any - * query elements that are themselves arrays will be imploded into a comma separated list. - * - * @return string the assembled URL - */ - private function buildUrl($resourcePath, $options) - { - $url = "/{$this->endpoint}/"; - if (!is_null($resourcePath)) { - $url .= $resourcePath; - } - - if (!empty($options['query'])) { - // check each query element - if it's an array, implode it to match the API-accepted format - foreach ($options['query'] as &$element) { - if (is_array($element)) { - $element = implode(',', $element); - } - } - - $queryString = http_build_query($options['query']); - $url .= '?'.$queryString; - } - - return $url; - } - - /** - * Prepares a body for put and post requests. - * - * @param array $options array with an optional value of body with values to build a request body from. - * - * @return string|null A json encoded string or null if no body was provided - */ - private function buildBody($options) - { - $body = null; - if (!empty($options['body'])) { - $model = static::$structure; - $requestModel = $this->buildRequestModel($options['body'], $model); - $body = json_encode($requestModel); - } - - return $body; - } - - /** - * Private Method for issuing GET and DELETE request to current API endpoint. - * - * This method is responsible for getting the collection _and_ - * a specific entity from the API endpoint - * - * If resourcePath parameter is omitted, then we fetch the collection - * - * @param string $action HTTP method type - * @param string $resourcePath (optional) string resource path of specific resource - * @param array $options (optional) query string parameters - * - * @return array Result set of action performed on resource - * - * @throws APIResponseException - */ - private function callResource($action, $resourcePath = null, $options = []) - { - $action = strtoupper($action); // normalize - - $url = $this->buildUrl($resourcePath, $options); - $body = $this->buildBody($options); - - //make request - try { - $response = $this->sparkpost->httpAdapter->send($url, $action, $this->sparkpost->getHttpHeaders(), $body); - - $statusCode = $response->getStatusCode(); - - // Handle 4XX responses, 5XX responses will throw an HttpAdapterException - if ($statusCode < 400) { - return json_decode($response->getBody()->getContents(), true); - } elseif ($statusCode === 403) { - $response = json_decode($response->getBody(), true); - throw new APIResponseException( - 'Request forbidden', - $statusCode, - isset($response['errors'][0]['message']) ? $response['errors'][0]['message'] : 'Request forbidden', - isset($response['errors'][0]['code']) ? $response['errors'][0]['code'] : 1100, - isset($response['errors'][0]['description']) ? $response['errors'][0]['description'] : 'Does this API Key have the correct permissions?' - ); - } elseif ($statusCode === 404) { - throw new APIResponseException('The specified resource does not exist', 404); - } else { - $response = json_decode($response->getBody(), true); - throw new APIResponseException( - 'Received bad response from '.ucfirst($this->endpoint), - $statusCode, - isset($response['errors'][0]['message']) ? $response['errors'][0]['message'] : '', - isset($response['errors'][0]['code']) ? $response['errors'][0]['code'] : 0, - isset($response['errors'][0]['description']) ? $response['errors'][0]['description'] : '' - ); - } - } - - /* - * Configuration Errors, and a catch all for other errors - */ - catch (\Exception $exception) { - if ($exception instanceof APIResponseException) { - throw $exception; - } - - throw new APIResponseException('Unable to contact '.ucfirst($this->endpoint).' API: '.$exception->getMessage(), $exception->getCode()); - } - } -} diff --git a/lib/SparkPost/APIResponseException.php b/lib/SparkPost/APIResponseException.php deleted file mode 100644 index a491b3c..0000000 --- a/lib/SparkPost/APIResponseException.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php - -namespace SparkPost; - -class APIResponseException extends \Exception -{ - /** - * @var string - */ - protected $apiMessage; - - /** - * @var int - */ - protected $apiCode; - - /** - * @var string - */ - protected $apiDescription; - - /** - * Construct the exception. - */ - public function __construct($message = '', $code = 0, $apiMessage = '', $apiCode = 0, $apiDescription = '') - { - $this->apiMessage = $apiMessage; - $this->apiCode = $apiCode; - $this->apiDescription = $apiDescription; - parent::__construct($message, $code); - } - - /** - * Gets the Exception message. - * - * @return string the Exception message as a string. - */ - public function getAPIMessage() - { - return $this->apiMessage; - } - - /** - * Gets the API Exception code. - * - * @return int the exception code as integer. - */ - public function getAPICode() - { - return $this->apiCode; - } - - /** - * Gets the Exception description. - * - * @return string the Exception description as a string. - */ - public function getAPIDescription() - { - return $this->apiDescription; - } -} diff --git a/lib/SparkPost/MessageEvents.php b/lib/SparkPost/MessageEvents.php deleted file mode 100644 index d44a30f..0000000 --- a/lib/SparkPost/MessageEvents.php +++ /dev/null @@ -1,64 +0,0 @@ -<?php - -namespace SparkPost; - -/** - * SDK class for querying the Message Events API. - * - * @see https://developers.sparkpost.com/api/#/reference/message-events - */ -class MessageEvents extends APIResource -{ - /** - * @var string - */ - public $endpoint = 'message-events'; - - /** - * Method for issuing search requests to the Message Events API. - * - * The method passes-through all of the query parameters - the valid ones are listed at - * - * @link https://developers.sparkpost.com/api/#/reference/message-events/events-documentation/search-for-message-events - * - * @param array $queryParams The query parameters. Note that a query parameter containing an array - * is collapsed into a comma-separated list. - * - * @return array The result of the query. - */ - public function search(array $queryParams) - { - // check for DateTime objects & replace them with the formatted string equivalent - foreach (['from', 'to'] as $dateTimeParam) { - if (isset($queryParams[$dateTimeParam]) && $queryParams[$dateTimeParam] instanceof \DateTime) { - // the message events API doesn't allow the seconds or GMT offset, so strip them - $queryParams[$dateTimeParam] = substr($queryParams[$dateTimeParam]->format(\DateTime::ATOM), 0, 16); - } - } - - return $this->get(null, $queryParams); - } - - /** - * List descriptions of the event fields that could be included in a response from the MessageEvent::search() method. - * - * @return array The event field descriptions. - */ - public function documentation() - { - return $this->get('events/documentation'); - } - - /** - * List examples of the event data that will be included in a response from the MessageEvent::search() method. - * - * @param array $events (optional) Event types for which to get a sample payload. If not provided, samples - * for all events will be returned. - * - * @return array Sample events. - */ - public function samples(array $events = []) - { - return $this->get('events/samples', ['events' => $events]); - } -} diff --git a/lib/SparkPost/SparkPost.php b/lib/SparkPost/SparkPost.php index ff8b456..e76bcd0 100644 --- a/lib/SparkPost/SparkPost.php +++ b/lib/SparkPost/SparkPost.php @@ -2,151 +2,238 @@ namespace SparkPost; -use Ivory\HttpAdapter\Configuration; -use Ivory\HttpAdapter\HttpAdapterInterface; +use Http\Client\HttpClient; +use Http\Client\HttpAsyncClient; +use GuzzleHttp\Psr7\Request as Request; class SparkPost { - public $transmission; - public $messageEvents; - /** * Library version, used for setting User-Agent. */ - private $version = '1.2.1'; + private $version = '2.0.0'; /** - * Connection config for making requests. + * HttpClient used to make requests. */ - private $config; + public $httpClient; /** - * @var \Ivory\HttpAdapter\HttpAdapterInterface to make requests through. + * Options for requests. */ - public $httpAdapter; + private $options; /** - * Default config values. Passed in values will override these. + * Default options for requests that can be overridden with the setOptions function. */ - private static $apiDefaults = [ + private static $defaultOptions = [ 'host' => 'api.sparkpost.com', 'protocol' => 'https', 'port' => 443, - 'strictSSL' => true, 'key' => '', 'version' => 'v1', - 'timeout' => 10 + 'timeout' => 10, + 'async' => true, ]; /** - * Sets up httpAdapter and config. - * - * Sets up instances of sub libraries. + * Instance of Transmission class. + */ + public $transmissions; + + /** + * Sets up the SparkPost instance. + * + * @param HttpClient $httpClient - An httplug client or adapter + * @param array $options - An array to overide default options or a string to be used as an API key + */ + public function __construct(HttpClient $httpClient, $options) + { + $this->setOptions($options); + $this->setHttpClient($httpClient); + $this->setupEndpoints(); + } + + /** + * Sends either sync or async request based on async option. * - * @param \Ivory\HttpAdapter\HttpAdapterInterface $httpAdapter - An adapter for making http requests - * @param string | array $settingsConfig - Hashmap that contains config values - * for the SDK to connect to SparkPost. If its a string we assume that - * its just they API Key. + * @param string $method + * @param string $uri + * @param array $payload - either used as the request body or url query params + * @param array $headers + * + * @return SparkPostPromise or SparkPostResponse depending on sync or async request */ - public function __construct($httpAdapter, $settingsConfig) + public function request($method = 'GET', $uri = '', $payload = [], $headers = []) { - //config needs to be setup before adapter because of default adapter settings - $this->setConfig($settingsConfig); - $this->setHttpAdapter($httpAdapter); + if ($this->options['async'] === true) { + return $this->asyncRequest($method, $uri, $payload, $headers); + } else { + return $this->syncRequest($method, $uri, $payload, $headers); + } + } - $this->transmission = new Transmission($this); - $this->messageEvents = new MessageEvents($this); + /** + * Sends sync request to SparkPost API. + * + * @param string $method + * @param string $uri + * @param array $payload + * @param array $headers + * + * @return SparkPostResponse + * + * @throws SparkPostException + */ + public function syncRequest($method = 'GET', $uri = '', $payload = [], $headers = []) + { + $request = $this->buildRequest($method, $uri, $payload, $headers); + try { + return new SparkPostResponse($this->httpClient->sendRequest($request)); + } catch (\Exception $exception) { + throw new SparkPostException($exception); + } } /** - * Creates an unwrapped api interface for endpoints that aren't yet supported. - * The new resource is attached to this object as well as returned. + * Sends async request to SparkPost API. * - * @param string $endpoint + * @param string $method + * @param string $uri + * @param array $payload + * @param array $headers + * + * @return SparkPostPromise + */ + public function asyncRequest($method = 'GET', $uri = '', $payload = [], $headers = []) + { + if ($this->httpClient instanceof HttpAsyncClient) { + $request = $this->buildRequest($method, $uri, $payload, $headers); + + return new SparkPostPromise($this->httpClient->sendAsyncRequest($request)); + } else { + throw new \Exception('Your http client does not support asynchronous requests. Please use a different client or use synchronous requests.'); + } + } + + /** + * Builds request from given params. + * + * @param string $method + * @param string $uri + * @param array $payload + * @param array $headers * - * @return APIResource - the unwrapped resource + * @return GuzzleHttp\Psr7\Request - A Psr7 compliant request */ - public function setupUnwrapped($endpoint) + public function buildRequest($method, $uri, $payload, $headers) { - $this->{$endpoint} = new APIResource($this); - $this->{$endpoint}->endpoint = $endpoint; + $method = trim(strtoupper($method)); + + if ($method === 'GET') { + $params = $payload; + $body = []; + } else { + $params = []; + $body = $payload; + } - return $this->{$endpoint}; + $url = $this->getUrl($uri, $params); + $headers = $this->getHttpHeaders($headers); + + return new Request($method, $url, $headers, json_encode($body)); } /** - * Merges passed in headers with default headers for http requests. + * Returns an array for the request headers. + * + * @param array $headers - any custom headers for the request + * + * @return array $headers - headers for the request */ - public function getHttpHeaders() + public function getHttpHeaders($headers = []) { - $defaultOptions = [ - 'Authorization' => $this->config['key'], + $constantHeaders = [ + 'Authorization' => $this->options['key'], 'Content-Type' => 'application/json', + 'User-Agent' => 'php-sparkpost/'.$this->version, ]; - return $defaultOptions; + foreach ($constantHeaders as $key => $value) { + $headers[$key] = $value; + } + + return $headers; } /** - * Helper function for getting the configuration for http requests. + * Builds the request url from the options and given params. * - * @param array $config + * @param string $path - the path in the url to hit + * @param array $params - query parameters to be encoded into the url * - * @return Configuration + * @return string $url - the url to send the desired request to */ - private function getHttpConfig($config) + public function getUrl($path, $params = []) { - // create Configuration for http adapter - $httpConfig = new Configuration(); - $baseUrl = $config['protocol'].'://'.$config['host'].($config['port'] ? ':'.$config['port'] : '').'/api/'.$config['version']; - $httpConfig->setBaseUri($baseUrl); - $httpConfig->setTimeout($this->config['timeout']); - $httpConfig->setUserAgent('php-sparkpost/'.$this->version); - - return $httpConfig; + $options = $this->options; + + $paramsArray = []; + foreach ($params as $key => $value) { + if (is_array($value)) { + $value = implode(',', $value); + } + + array_push($paramsArray, $key.'='.$value); + } + + $paramsString = implode('&', $paramsArray); + + return $options['protocol'].'://'.$options['host'].($options['port'] ? ':'.$options['port'] : '').'/api/'.$options['version'].'/'.$path.($paramsString ? '?'.$paramsString : ''); } - /** - * Validates and sets up the httpAdapter. - * - * @param $httpAdapter \Ivory\HttpAdapter\HttpAdapterInterface to make requests through. + /** + * Sets $httpClient to be used for request. * - * @throws \Exception + * @param Http\Client\HttpClient $httpClient - the client to be used for request */ - public function setHttpAdapter(HttpAdapterInterface $httpAdapter) + public function setHttpClient(HttpClient $httpClient) { - $this->httpAdapter = $httpAdapter; - $this->httpAdapter->setConfiguration($this->getHttpConfig($this->config)); + $this->httpClient = $httpClient; } /** - * Allows the user to pass in values to override the defaults and set their API key. - * - * @param string | array $settingsConfig - Hashmap that contains config values - * for the SDK to connect to SparkPost. If its a string we assume that - * its just they API Key. + * Sets the options from the param and defaults for the SparkPost object. * - * @throws \Exception + * @param array $options - either an string API key or an array of options */ - public function setConfig($settingsConfig) + public function setOptions($options) { - // if the config map is a string we should assume that its an api key - if (is_string($settingsConfig)) { - $settingsConfig = ['key' => $settingsConfig]; + // if the options map is a string we should assume that its an api key + if (is_string($options)) { + $options = ['key' => $options]; } // Validate API key because its required - if (!isset($settingsConfig['key']) || !preg_match('/\S/', $settingsConfig['key'])) { + if (!isset($this->options['key']) && (!isset($options['key']) || !preg_match('/\S/', $options['key']))) { throw new \Exception('You must provide an API key'); } - $this->config = self::$apiDefaults; + $this->options = isset($this->options) ? $this->options : self::$defaultOptions; - // set config, overriding defaults - foreach ($settingsConfig as $configOption => $configValue) { - if (key_exists($configOption, $this->config)) { - $this->config[$configOption] = $configValue; + // set options, overriding defaults + foreach ($options as $option => $value) { + if (key_exists($option, $this->options)) { + $this->options[$option] = $value; } } } + + /** + * Sets up any endpoints from custom classes e.g. $this->transmissions. + */ + private function setupEndpoints() + { + // $this->transmissions = new Transmission($this); + } } diff --git a/lib/SparkPost/SparkPostException.php b/lib/SparkPost/SparkPostException.php new file mode 100644 index 0000000..ca92e24 --- /dev/null +++ b/lib/SparkPost/SparkPostException.php @@ -0,0 +1,41 @@ +<?php + +namespace SparkPost; + +use Http\Client\Exception\HttpException as HttpException; + +class SparkPostException extends \Exception +{ + /** + * Variable to hold json decoded body from http response. + */ + private $body = null; + + /** + * Sets up the custom exception and copies over original exception values. + * + * @param Exception $exception - the exception to be wrapped + */ + public function __construct(\Exception $exception) + { + $message = $exception->getMessage(); + $code = $exception->getCode(); + if ($exception instanceof HttpException) { + $message = $exception->getResponse()->getBody()->__toString(); + $this->body = json_decode($message, true); + $code = $exception->getResponse()->getStatusCode(); + } + + parent::__construct($message, $code, $exception->getPrevious()); + } + + /** + * Returns the body. + * + * @return array $body - the json decoded body from the http response + */ + public function getBody() + { + return $this->body; + } +} diff --git a/lib/SparkPost/SparkPostPromise.php b/lib/SparkPost/SparkPostPromise.php new file mode 100644 index 0000000..15f129f --- /dev/null +++ b/lib/SparkPost/SparkPostPromise.php @@ -0,0 +1,69 @@ +<?php + +namespace SparkPost; + +use Http\Promise\Promise as HttpPromise; + +class SparkPostPromise implements HttpPromise +{ + /** + * HttpPromise to be wrapped by SparkPostPromise. + */ + private $promise; + + /** + * set the promise to be wrapped. + * + * @param HttpPromise $promise + */ + public function __construct(HttpPromise $promise) + { + $this->promise = $promise; + } + + /** + * Hand off the response functions to the original promise and return a custom response or exception. + * + * @param callable $onFulfilled - function to be called if the promise is fulfilled + * @param callable $onRejected - function to be called if the promise is rejected + */ + public function then(callable $onFulfilled = null, callable $onRejected = null) + { + return $this->promise->then(function($response) use ($onFulfilled) { + if (isset($onFulfilled)) + $onFulfilled(new SparkPostResponse($response)); + }, function($exception) use ($onRejected) { + if (isset($onRejected)) + $onRejected(new SparkPostException($exception)); + }); + } + + /** + * Hand back the state. + * + * @return $state - returns the state of the promise + */ + public function getState() + { + return $this->promise->getState(); + } + + /** + * Wraps the wait function and returns a custom response or throws a custom exception. + * + * @param bool $unwrap + * + * @return SparkPostResponse + * + * @throws SparkPostException + */ + public function wait($unwrap = true) + { + try { + $response = $this->promise->wait($unwrap); + return $response ? new SparkPostResponse($response) : $response; + } catch (\Exception $exception) { + throw new SparkPostException($exception); + } + } +} diff --git a/lib/SparkPost/SparkPostResponse.php b/lib/SparkPost/SparkPostResponse.php new file mode 100644 index 0000000..9104b33 --- /dev/null +++ b/lib/SparkPost/SparkPostResponse.php @@ -0,0 +1,105 @@ +<?php + +namespace SparkPost; + +use Psr\Http\Message\ResponseInterface as ResponseInterface; +use Psr\Http\Message\StreamInterface as StreamInterface; + +class SparkPostResponse implements ResponseInterface +{ + /** + * ResponseInterface to be wrapped by SparkPostResponse. + */ + private $response; + + /** + * set the response to be wrapped. + * + * @param ResponseInterface $response + */ + public function __construct(ResponseInterface $response) + { + $this->response = $response; + } + + /** + * Returns the body. + * + * @return array $body - the json decoded body from the http response + */ + public function getBody() + { + $body = $this->response->getBody(); + $body_string = $body->__toString(); + + $json = json_decode($body_string, true); + + return $json; + } + + // pass these down to the response given in the constructor + public function getProtocolVersion() + { + return $this->response->getProtocolVersion(); + } + + public function withProtocolVersion($version) + { + return $this->response->withProtocolVersion($version); + } + + public function getHeaders() + { + return $this->response->getHeaders(); + } + + public function hasHeader($name) + { + return $this->response->hasHeader($name); + } + + public function getHeader($name) + { + return $this->response->getHeader($name); + } + + public function getHeaderLine($name) + { + return $this->response->getHeaderLine($name); + } + + public function withHeader($name, $value) + { + return $this->response->withHeader($name, $value); + } + + public function withAddedHeader($name, $value) + { + return $this->response->withAddedHeader($name, $value); + } + + public function withoutHeader($name) + { + return $this->response->withoutHeader($name); + } + + public function withBody(StreamInterface $body) + { + return $this->response->withBody($body); + } + + public function getStatusCode() + { + return $this->response->getStatusCode(); + } + + public function withStatus($code, $reasonPhrase = '') + { + return $this->response->withStatus($code, $reasonPhrase); + } + + public function getReasonPhrase() + { + return $this->response->getReasonPhrase(); + } +} diff --git a/lib/SparkPost/Transmission.php b/lib/SparkPost/Transmission.php deleted file mode 100644 index ff63722..0000000 --- a/lib/SparkPost/Transmission.php +++ /dev/null @@ -1,136 +0,0 @@ -<?php - -namespace SparkPost; - -/** - * SDK interface for managing transmissions. - */ -class Transmission extends APIResource -{ - public $endpoint = 'transmissions'; - - /** - * Mapping for values passed into the send method to the values needed for the Transmission API. - * - * @var array - */ - protected static $parameterMappings = [ - 'attachments' => 'content.attachments', - 'campaign' => 'campaign_id', - 'customHeaders' => 'content.headers', - 'description' => 'description', - 'from' => 'content.from', - 'html' => 'content.html', - 'inlineCss' => 'options.inline_css', - 'inlineImages' => 'content.inline_images', - 'metadata' => 'metadata', - 'recipientList' => 'recipients.list_id', - 'recipients' => 'recipients', - 'replyTo' => 'content.reply_to', - 'returnPath' => 'return_path', - 'rfc822' => 'content.email_rfc822', - 'sandbox' => 'options.sandbox', - 'startTime' => 'options.start_time', - 'subject' => 'content.subject', - 'substitutionData' => 'substitution_data', - 'template' => 'content.template_id', - 'text' => 'content.text', - 'trackClicks' => 'options.click_tracking', - 'trackOpens' => 'options.open_tracking', - 'transactional' => 'options.transactional', - 'useDraftTemplate' => 'use_draft_template', - ]; - - /** - * Sets up default structure and default values for the model that is acceptable by the API. - * - * @var array - */ - protected static $structure = [ - 'return_path' => 'default@sparkpostmail.com', - 'content' => [ - 'html' => null, - 'text' => null, - 'email_rfc822' => null, - ], - 'use_draft_template' => false, - ]; - - /** - * Method for issuing POST request to the Transmissions API. - * - * This method assumes that all the appropriate fields have - * been populated by the user through configuration. Acceptable - * configuration values are: - * 'attachments': array, - * 'campaign': string, - * 'customHeaders': array, - * 'description': string, - * 'from': string, - * 'html': string, - * 'inlineCss': boolean, - * 'inlineImages': array, - * 'metadata': array, - * 'recipientList': string, - * 'recipients': array, - * 'replyTo': string, - * 'rfc822': string, - * 'sandbox': boolean, - * 'startTime': string | \DateTime, - * 'subject': string, - * 'substitutionData': array, - * 'template': string, - * 'text': string, - * 'trackClicks': boolean, - * 'trackOpens': boolean, - * 'transactional': boolean, - * 'useDraftTemplate': boolean - * - * @param array $transmissionConfig - * - * @return array API repsonse represented as key-value pairs - */ - public function send($transmissionConfig) - { - if (isset($transmissionConfig['startTime']) && $transmissionConfig['startTime'] instanceof \DateTime) { - $transmissionConfig['startTime'] = $transmissionConfig['startTime']->format(\DateTime::ATOM); - } - - return $this->create($transmissionConfig); - } - - /** - * Method for retrieving information about all transmissions - * Wrapper method for a cleaner interface. - * - * @param null|string $campaignID - * @param null|string $templateID - * - * @return array result Set of transmissions - */ - public function all($campaignID = null, $templateID = null) - { - $options = []; - if ($campaignID !== null) { - $options['campaign_id'] = $campaignID; - } - if ($templateID !== null) { - $options['template_id'] = $templateID; - } - - return $this->get(null, $options); - } - - /** - * Method for retrieving information about a single transmission - * Wrapper method for a cleaner interface. - * - * @param string $transmissionID Identifier of the transmission to be found - * - * @return array result Single transmission represented in key-value pairs - */ - public function find($transmissionID) - { - return $this->get($transmissionID); - } -} |