[
  {
    "path": ".coveralls.yml",
    "content": "# single file\ncoverage_clover: test/output/clover.xml\njson_path: test/output/coveralls-upload.json\n"
  },
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\ntrim_trailing_whitespace = true\n\n[*.md]\ntrim_trailing_whitespace = false\n\n[*.yml]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: php\nphp:\n  - '7.2'\n  - '7.3'\n  - '7.4'\n  - '8.0'\ninstall:\n  - composer install --no-interaction\nscript:\n  - mkdir -p test/output/report\n  - composer test\nafter_script:\n  - php vendor/bin/php-coveralls\nnotifications:\n  slack:\n    secure: mw6HF2KR0YwYcIaYvV6qjuWC+XSIP8SQOe13VwmGf3b783hMcZDZTUS9N4bIfpwYi74A9qmzKdc425OSu45nceAf7hzFusCY5rYMoLQK/ksJ7sd+ay7tWhPRuomG1w8idTyXtzce23zOfBtOCHQakbavH2Uz6mh5lJYPFlMKW4c=\n"
  },
  {
    "path": "AUTHORS.md",
    "content": "php-sparkpost is maintained by Message Systems.\n\n# Contributors\n\n* Jordan Nornhold, [@beardyman](https://github.com/beardyman)\n* Rich Leland, [@richleland](https://github.com/richleland)\n* Jason Rhodes [@jasonrhodes](https://github.com/jasonrhodes)\n* Matthew April, [@MattApril](https://github.com/MattApril)\n* James Fellows, [@j4m3s](https://github.com/j4m3s)\n* LF Bittencourt, [@lfbittencourt](https://github.com/lfbittencourt)\n* Jakub Piasecki, [@zaporylie](https://github.com/zaporylie)\n* Danil Zakablukovskiy, [@djagya](https://github.com/djagya)\n* Chris Wilson, [@yepher](https://github.com/yepher)\n* Maxim Dzhuliy, [@max-si-m](https://github.com/max-si-m)\n* [@chandon](https://github.com/chandon)\n* Avi Goldman, [@avrahamgoldman](https://github.com/avrahamgoldman)\n* Vincent Song, [@vwsong](https://github.com/vwsong)\n* Tobias Nyholm, [@Nyholm](https://github.com/Nyholm)\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\nAll notable changes to this project will be documented in this file.\nThis project adheres to [Semantic Versioning](http://semver.org/).\n\n## [Unreleased][unreleased]\n\n## [2.3.0] - 2021-03-16\n- [#201](https://github.com/SparkPost/php-sparkpost/pull/201) Update examples, README\n- [#200](https://github.com/SparkPost/php-sparkpost/pull/200) PHP 8 support\n\n## [2.2.1] - 2021-03-08\n- [#198](https://github.com/SparkPost/php-sparkpost/pull/198) Address #197: No longer need formfeed replacement. README work.\n- [#191](https://github.com/SparkPost/php-sparkpost/pull/191) Updating License\n\n## [2.2.0] - 2019-06-04\n- [#187](https://github.com/SparkPost/php-sparkpost/pull/187) Updated composer.json\n- [#169](https://github.com/SparkPost/php-sparkpost/pull/169) Optional automatic retry on 5xx\n- [#166](https://github.com/SparkPost/php-sparkpost/pull/166/files) Quick fix for using the API without composer\n- [#149](https://github.com/SparkPost/php-sparkpost/pull/149) Setters should return current object\n\n## [2.1.0] - 2017-01-09\n### Added\n- [#161](https://github.com/SparkPost/php-sparkpost/pull/161) added example for sending email with attachment and simplified the examples setup\n- [#159](https://github.com/SparkPost/php-sparkpost/pull/159) added `debug` option for seeing the full request sent to SparkPost\n- [#151](https://github.com/SparkPost/php-sparkpost/pull/151) added packagist badges\n- [#139](https://github.com/SparkPost/php-sparkpost/pull/139) added examples for message events and templates\n\n### Changed\n- [#150](https://github.com/SparkPost/php-sparkpost/issues/150) renamed the `Resource` class to `ResourceBase` since resource soft reserved in php 7\n- [#137](https://github.com/SparkPost/php-sparkpost/pull/137) cleaned up tests and post install scripts\n- [#138](https://github.com/SparkPost/php-sparkpost/pull/138) added PHP 7.1 as a test environment\n\n### Fixed\n- [#156](https://github.com/SparkPost/php-sparkpost/pull/156) fixed typo in README.md\n- [#152](https://github.com/SparkPost/php-sparkpost/issues/152) fixed propagation of coverage tests to coveralls.io\n- [#147](https://github.com/SparkPost/php-sparkpost/pull/147) fixed examples in README.md\n- [#139](https://github.com/SparkPost/php-sparkpost/pull/139) fixed the ability to send using recipient lists\n- Issue[#141](https://github.com/SparkPost/php-sparkpost/issues/141) removed form feeds from the JSON body sent to the API\n\n## [2.0.3] - 2016-07-28\n### Fixed\n- Issue [#135](https://github.com/SparkPost/php-sparkpost/issues/135) reported `Http\\Discovery\\NotFoundException` caused by 2.0.2 update.\n\n## [2.0.2] - 2016-07-28\n### Fixed\n- [#131](https://github.com/SparkPost/php-sparkpost/pull/131) removed any dependency on Guzzle by replacing it with `MessageFactoryDiscovery`\n\n\n## [2.0.1] - 2016-06-29\n### Fixed\n- [#129](https://github.com/SparkPost/php-sparkpost/pull/129) issue with `content.from` being expected even when using a stored template\n\n## [2.0.0] - 2016-06-24\n\nThis major release included a complete refactor of the library to be a thin HTTP client layer with some sugar methods on the Transmission class. There is now a base resource that can be used to call any SparkPost API with a one to one mapping of payload parameters to what is listed in our API documentation.\n\n### Changed\n- [#123](https://github.com/SparkPost/php-sparkpost/pull/123) Rewrote docs and updated composer name\n- [#122](https://github.com/SparkPost/php-sparkpost/pull/122) Add transmission class and examples\n- [#121](https://github.com/SparkPost/php-sparkpost/pull/121) Update base resource and tests\n\n## [1.2.1] - 2016-05-27\n### Fixed\n- [#111](https://github.com/SparkPost/php-sparkpost/pull/111) allow pass through of timeout setting in http config\n\n## [1.2.0] - 2016-05-04\n### Added\n- [EditorConfig](http://editorconfig.org/) file to maintain consistent coding style\n- `composer run-script fix-style` can now be run to enforce PSR-2 style\n\n### Changed\n- Responses from the SparkPost API with HTTP status code 403 now properly raise with message, code, and description\n\n### Fixed\n- Removed reliance on composer for version of library\n\n## [1.1.0] - 2016-05-02\n### Added\n- Message Events API added.\n\n### Changed\n- Transmission API now accepts a DateTime object for startDate\n\n## [1.0.3] - 2016-03-25\n### Added\n- Support for attachments, inline attachments, inline css, sandbox, start time, and transactional options in `Transmission` class\n- API response exceptions now include message, code, and description from API\n\n## [1.0.2] - 2016-02-28\n### Fixed\n- Miscellaneous code cleanups related to docs and namespacing\n\n## [1.0.1] - 2016-02-24\n### Added\n- Example for using `setupUnwrapped()` to get a list of webhooks.\n- CHANGELOG.md for logging release updates and backfilled it with previous release.\n\n### Fixed\n- Library will now throw a `SparkPost\\APIReponseException` properly when a 4XX http status is encountered.\n\n## 1.0.0 - 2015-10-15\n### Added\n- Request adapter interface for passing in request adapters via `Ivory\\HttpAdapter`\n- Ability to create 'unwrapped' modules for API endpoints that haven't had functionality included yet.\n- Instructions for setting up request adapters in README\n\n### Changed\n- Library now requires PHP 5.5 or greater\n- Updated interface to be instance based with referenceable objects rather than static functions.\n\n### Fixed\n- README now has proper code blocks denoting PHP language\n\n[unreleased]: https://github.com/sparkpost/php-sparkpost/compare/2.2.1...HEAD\n[2.2.1]: https://github.com/sparkpost/php-sparkpost/compare/2.2.0...2.2.1\n[2.2.0]: https://github.com/sparkpost/php-sparkpost/compare/2.1.0...2.2.0\n[2.1.0]: https://github.com/sparkpost/php-sparkpost/compare/2.0.3...2.1.0\n[2.0.3]: https://github.com/sparkpost/php-sparkpost/compare/2.0.2...2.0.3\n[2.0.2]: https://github.com/sparkpost/php-sparkpost/compare/2.0.1...2.0.2\n[2.0.1]: https://github.com/sparkpost/php-sparkpost/compare/2.0.0...2.0.1\n[2.0.0]: https://github.com/sparkpost/php-sparkpost/compare/1.2.1...2.0.0\n[1.2.1]: https://github.com/sparkpost/php-sparkpost/compare/1.2.0...1.2.1\n[1.2.0]: https://github.com/sparkpost/php-sparkpost/compare/v1.1.0...1.2.0\n[1.1.0]: https://github.com/sparkpost/php-sparkpost/compare/v1.0.3...v1.1.0\n[1.0.3]: https://github.com/sparkpost/php-sparkpost/compare/v1.0.2...v1.0.3\n[1.0.2]: https://github.com/sparkpost/php-sparkpost/compare/v1.0.1...v1.0.2\n[1.0.1]: https://github.com/sparkpost/php-sparkpost/compare/v1.0.0...v1.0.1\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to php-sparkpost\nTransparency is one of our core values, and we encourage developers to contribute and become part of the SparkPost developer community.\n\nThe following is a set of guidelines for contributing to php-sparkpost,\nwhich is hosted in the [SparkPost Organization](https://github.com/sparkpost) on GitHub.\nThese are just guidelines, not rules, use your best judgment and feel free to\npropose changes to this document in a pull request.\n\n## Submitting Issues\n* You can create an issue [here](https://github.com/sparkpost/php-sparkpost/issues/new), but\n  before doing that please read the notes below on debugging and submitting issues,\n  and include as many details as possible with your report.\n* Include the version of php-sparkpost you are using.\n* Perform a [cursory search](https://github.com/SparkPost/php-sparkpost/issues?q=is%3Aissue+is%3Aopen)\n  to see if a similar issue has already been submitted.\n\n## Development\n\n### Setup (Getting the Tools)\n#### Install Composer\n```\ncurl -sS https://getcomposer.org/installer | php\n```\n\nAdd composer install directory to $PATH `~/.composer/vendor/bin/`\n\n### phpenv\n\n[phpenv](https://github.com/phpenv/phpenv-installer) is useful for testing locally across different PHP versions.\n\n### Developing your app against a local version of the SparkPost library\n\nIf you're working on the library and your app together, you can tell Composer to get `php-sparkpost` from a local path. With a directory structure such as:\n\nhome\n - php-sparkpost\n - my-app\n    - composer.json\n    - .. etc\n\nUse the following for `my-app/composer.json`:\n```json\n{\n    \"name\": \"sparkpost/php_simple_email_send\",\n    \"description\": \"a small test program to send an email\",\n    \"repositories\": [\n        {\n            \"type\": \"path\",\n            \"url\": \"../php-sparkpost\"\n        }\n    ],\n    \"require\": {\n        \"php-http/guzzle6-adapter\": \"^1.1\",\n        \"guzzlehttp/guzzle\": \"^6.0\",\n        \"sparkpost/sparkpost\": \"dev-master\"\n    }\n}\n```\n\n\n### Memory\nWe recommend increasing PHP’s memory limit, by default it uses 128MB.  We ran into some issues during local development without doing so.  You can do this by editing your php.ini file and modifying `memory_limit`.  We set ours to `memory_limit = 1024M`.\n\n#### Install XDebug for code coverage generation\nFollow the instructions at [xdebug.org](http://xdebug.org/wizard.php)\n\n#### Development Tool Resources\n* https://getcomposer.org/doc/00-intro.md#globally-on-osx-via-homebrew-\n* https://phpunit.de/manual/current/en/installation.html\n\n### Local Development\n* Fork [this repository](http://github.com/SparkPost/php-sparkpost)\n* Clone your fork\n* Run `composer install`\n* Write code!\n\n### Contribution Steps\n\n#### Guidelines\n\n- Provide documentation for any newly added code.\n- Provide tests for any newly added code.\n- Follow [PSR-2](http://www.php-fig.org/psr/psr-2/) (_will be auto-enforced by php-cs-fixer in a later step_)\n\n1. Create a new branch named after the issue you’ll be fixing (include the issue number as the branch name, example: Issue in GH is #8 then the branch name should be ISSUE-8)\n1. Write corresponding tests and code (only what is needed to satisfy the issue and tests please)\n    * Include your tests in the 'test' directory in an appropriate test file\n    * Write code to satisfy the tests\n1. Ensure automated tests pass\n1. Run `composer run-script fix-style` to enforce PSR-2 style\n1. Send a pull request and bug the maintainer until it gets merged and published. :) Make sure to add yourself to [AUTHORS](https://github.com/SparkPost/php-sparkpost/blob/master/AUTHORS.md).\n\n\n### Testing\nOnce you are setup for local development:\n* You can execute the unit tests using: `composer test`\n* You can view coverage information by viewing: `open test/output/report/index.html`\n\n## Releasing\n\n* Update version in the [library](https://github.com/SparkPost/php-sparkpost/blob/eeb6ba971584fcc4c12fd69247c6b24df7827af5/lib/SparkPost/SparkPost.php#L16) during development. This is used in the `user_agent` of your requests.\n\n* Once it's been merged down, create a release tag in git.\n* Composer will automatically pickup the new tag and present it as a release.\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright 2014 Message Systems, Inc. or its affiliates.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "MIGRATION.md",
    "content": "# Migration Guide\n\nThis is a guide to help you make the switch when the SparkPost PHP library changes major versions.\n\n## Migrating from 1.0 to 2.0\n\n## Package name change\nThe composer package name has changed from `sparkpost/php-sparkpost` to `sparkpost/sparkpost`\n\n### No more setupUnwrapped\nWe replaced the idea of 'wrapping' API resources with a simple `request` function. To see it in action, check out this [example](https://github.com/SparkPost/php-sparkpost/tree/2.0.0#send-an-api-call-using-the-base-request-function).\n\n### `transmission` becomes `transmissions`\nTransmission endpoints are now under `$sparky->transmissions` instead of `$sparky->transmission` to map more directly to the [API docs](https://developers.sparkpost.com/api/).\n\n* We no longer map parameters to the API - we simplified. Instead custom mapping, now set the payload to match the API docs.\n* The exceptions to the previous statement are `cc` and `bcc`. They are helpers to make it easier to add cc and bcc recipients. [Example](https://github.com/SparkPost/php-sparkpost/tree/2.0.0#send-an-email-using-the-transmissions-endpoint)\n\n### Switched from Ivory Http Adapter to HTTPlug\nIvory Http Adapter was deprecated in favor of HTTPlug.\n\n### Asynchronous support\nWe addeded in support for [asynchronous calls](https://github.com/SparkPost/php-sparkpost/tree/2.0.0#asynchronous) (assuming your client supports it).\n\n### Example\n#### 2.0\n```php\ntry {\n\t$sparky->setOptions([ 'async' => false ]);\n    // Build your email and send it!\n    $results = $sparky->transmissions->post([\n    \t'content'=>[\n\t        'from'=>[\n\t            'name' => 'From Envelope',\n\t            'email' => 'from@sparkpostbox.com>'\n\t        ],\n\t        'subject'=>'First Mailing From PHP',\n\t        'html'=>'<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent your very first mailing!</p></body></html>',\n\t        'text'=>'Congratulations, {{name}}!! You just sent your very first mailing!',\n\t    ],\n        'substitution_data'=>['name'=>'YOUR FIRST NAME'],\n        'recipients'=>[\n            [\n                'address'=>[\n                    'name'=>'YOUR FULL NAME',\n                    'email'=>'YOUR EMAIL ADDRESS'\n                ]\n            ]\n        ]\n    ]);\n    echo 'Woohoo! You just sent your first mailing!';\n} catch (\\Exception $err) {\n    echo 'Whoops! Something went wrong';\n    var_dump($err);\n}\n```\n\n#### 1.0\n```php\ntry {\n    // Build your email and send it!\n    $results = $sparky->transmission->send([\n        'from'=>[\n            'name' => 'From Envelope',\n            'email' => 'from@sparkpostbox.com>'\n        ],\n        'html'=>'<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent your very first mailing!</p></body></html>',\n        'text'=>'Congratulations, {{name}}!! You just sent your very first mailing!',\n        'substitutionData'=>['name'=>'YOUR FIRST NAME'],\n        'subject'=>'First Mailing From PHP',\n        'recipients'=>[\n            [\n                'address'=>[\n                    'name'=>'YOUR FULL NAME',\n                    'email'=>'YOUR EMAIL ADDRESS'\n                ]\n            ]\n        ]\n    ]);\n    echo 'Woohoo! You just sent your first mailing!';\n} catch (\\Exception $err) {\n    echo 'Whoops! Something went wrong';\n    var_dump($err);\n}\n```\n"
  },
  {
    "path": "README.md",
    "content": "<a href=\"https://www.sparkpost.com\"><img src=\"https://www.sparkpost.com/sites/default/files/attachments/SparkPost_Logo_2-Color_Gray-Orange_RGB.svg\" width=\"200px\"/></a>\n\n[Sign up](https://app.sparkpost.com/join?plan=free-0817?src=Social%20Media&sfdcid=70160000000pqBb&pc=GitHubSignUp&utm_source=github&utm_medium=social-media&utm_campaign=github&utm_content=sign-up) for a SparkPost account and visit our [Developer Hub](https://developers.sparkpost.com) for even more content.\n\n# SparkPost PHP Library\n\n[![Travis CI](https://travis-ci.org/SparkPost/php-sparkpost.svg?branch=master)](https://travis-ci.org/SparkPost/php-sparkpost)\n[![Coverage Status](https://coveralls.io/repos/SparkPost/php-sparkpost/badge.svg?branch=master&service=github)](https://coveralls.io/github/SparkPost/php-sparkpost?branch=master)\n[![Downloads](https://img.shields.io/packagist/dt/sparkpost/sparkpost.svg?maxAge=3600)](https://packagist.org/packages/sparkpost/sparkpost)\n[![Packagist](https://img.shields.io/packagist/v/sparkpost/sparkpost.svg?maxAge=3600)](https://packagist.org/packages/sparkpost/sparkpost)\n\nThe official PHP library for using [the SparkPost REST API](https://developers.sparkpost.com/api/).\n\nBefore using this library, you must have a valid API Key. To get an API Key, please log in to your SparkPost account and generate one in the Settings page.\n\n## Installation\n**Please note: The composer package `sparkpost/php-sparkpost` has been changed to `sparkpost/sparkpost` starting with version 2.0.**\n\nThe recommended way to install the SparkPost PHP Library is through composer.\n\n```\n# Install Composer\ncurl -sS https://getcomposer.org/installer | php\n```\n\nSparkpost requires php-http client (see [Setting up a Request Adapter](#setting-up-a-request-adapter)). There are several [providers](https://packagist.org/providers/php-http/client-implementation) available. If you were using guzzle6 your install might look like this.\n\n```\ncomposer require php-http/guzzle6-adapter \"^1.1\"\ncomposer require guzzlehttp/guzzle \"^6.0\"\n```\n\nNext, run the Composer command to install the SparkPost PHP Library:\n\n```\ncomposer require sparkpost/sparkpost\n```\n\nAfter installing, you need to require Composer's autoloader:\n\n```php\nrequire 'vendor/autoload.php';\nuse SparkPost\\SparkPost;\n```\n\n**Note:** Without composer the costs outweigh the benefits of using the PHP client library. A simple function like the one in [issue #164](https://github.com/SparkPost/php-sparkpost/issues/164#issuecomment-289888237) wraps the SparkPost API and makes it easy to use the API without resolving the composer dependencies.\n\n## Running with IDEs\n\nWhen running with `xdebug` under an IDE such as VS Code, you may see an exception is thrown in file `vendor/php-http/discovery/src/Strategy/PuliBetaStrategy.php`:\n\n```\nException has occurred.\nHttp\\Discovery\\Exception\\PuliUnavailableException: Puli Factory is not available\n```\n\n[This is usual](http://docs.php-http.org/en/latest/discovery.html#puli-factory-is-not-available). Puli is not required to use the library. You can resume running after the exception.\n\nYou can prevent the exception, by setting the discovery strategies, prior to creating the adapter object:\n```php\n// Prevent annoying \"Puli exception\" during work with xdebug / IDE\n// See https://github.com/getsentry/sentry-php/issues/801\n\\Http\\Discovery\\ClassDiscovery::setStrategies([\n        // \\Http\\Discovery\\Strategy\\PuliBetaStrategy::class, // Deliberately disabled\n        \\Http\\Discovery\\Strategy\\CommonClassesStrategy::class,\n        \\Http\\Discovery\\Strategy\\CommonPsr17ClassesStrategy::class,\n]);\n```\n\n## Setting up a Request Adapter\n\nBecause of dependency collision, we have opted to use a request adapter rather than\nrequiring a request library.  This means that your application will need to pass in\na request adapter to the constructor of the SparkPost Library.  We use the [HTTPlug](https://github.com/php-http/httplug) in SparkPost. Please visit their repo for a list of supported [clients and adapters](http://docs.php-http.org/en/latest/clients.html).  If you don't currently use a request library, you will\nneed to require one and create a client from it and pass it along. The example below uses the GuzzleHttp Client Library.\n\nA Client can be setup like so:\n\n```php\n<?php\nrequire 'vendor/autoload.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n$sparky = new SparkPost($httpClient, ['key'=>'YOUR_API_KEY']);\n?>\n```\n\n## Initialization\n#### new Sparkpost(httpClient, options)\n* `httpClient`\n    * Required: Yes\n    * HTTP client or adapter supported by HTTPlug\n* `options`\n    * Required: Yes\n    * Type: `String` or `Array`\n    * A valid Sparkpost API key or an array of options\n* `options.key`\n    * Required: Yes\n    * Type: `String`\n    * A valid Sparkpost API key\n* `options.host`\n    * Required: No\n    * Type: `String`\n    * Default: `api.sparkpost.com`\n* `options.protocol`\n    * Required: No\n    * Type: `String`\n    * Default: `https`\n* `options.port`\n    * Required: No\n    * Type: `Number`\n    * Default: 443\n* `options.version`\n    * Required: No\n    * Type: `String`\n    * Default: `v1`\n* `options.async`\n    * Required: No\n    * Type: `Boolean`\n    * Default: `true`\n    * `async` defines if the `request` function sends an asynchronous or synchronous request. If your client does not support async requests set this to `false`\n* `options.retries`\n    * Required: No\n    * Type: `Number`\n    * Default: `0`\n    * `retries` controls how many API call attempts the client makes after receiving a 5xx response\n* `options.debug`\n    * Required: No\n    * Type: `Boolean`\n    * Default: `false`\n    * If `debug` is true, then all `SparkPostResponse` and `SparkPostException` instances will return any array of the request values through the function `getRequest`\n\n## Methods\n### request(method, uri [, payload [, headers]])\n* `method`\n    * Required: Yes\n    * Type: `String`\n    * HTTP method for request\n* `uri`\n    * Required: Yes\n    * Type: `String`\n    * The URI to receive the request\n* `payload`\n    * Required: No\n    * Type: `Array`\n    * If the method is `GET` the values are encoded into the URL. Otherwise, if the method is `POST`, `PUT`, or `DELETE` the payload is used for the request body.\n* `headers`\n    * Required: No\n    * Type: `Array`\n    * Custom headers to be sent with the request.\n\n### syncRequest(method, uri [, payload [, headers]])\nSends a synchronous request to the SparkPost API and returns a `SparkPostResponse`\n\n### asyncRequest(method, uri [, payload [, headers]])\nSends an asynchronous request to the SparkPost API and returns a `SparkPostPromise`\n\n### setHttpClient(httpClient)\n* `httpClient`\n    *  Required: Yes\n    * HTTP client or adapter supported by HTTPlug\n\n### setOptions(options)\n* `options`\n    *  Required: Yes\n    *  Type: `Array`\n    * See constructor\n\n## Endpoints\n### transmissions\n* **post(payload)**\n    * `payload` - see request options\n    * `payload.cc`\n        * Required: No\n        * Type: `Array`\n        * Recipients to receive a carbon copy of the transmission\n    * `payload.bcc`\n        * Required: No\n        * Type: `Array`\n        * Recipients to discreetly receive a carbon copy of the transmission\n\n## Examples\n\n### Send An Email Using The Transmissions Endpoint\n```php\n<?php\nrequire 'vendor/autoload.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n// Good practice to not have API key literals in code - set an environment variable instead\n// For simple example, use synchronous model\n$sparky = new SparkPost($httpClient, ['key' => getenv('SPARKPOST_API_KEY'), 'async' => false]);\n\ntry {\n    $response = $sparky->transmissions->post([\n        'content' => [\n            'from' => [\n                'name' => 'SparkPost Team',\n                'email' => 'from@sparkpostbox.com',\n            ],\n            'subject' => 'First Mailing From PHP',\n            'html' => '<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent your very first mailing!</p></body></html>',\n            'text' => 'Congratulations, {{name}}!! You just sent your very first mailing!',\n        ],\n        'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],\n        'recipients' => [\n            [\n                'address' => [\n                    'name' => 'YOUR_NAME',\n                    'email' => 'YOUR_EMAIL',\n                ],\n            ],\n        ],\n        'cc' => [\n            [\n                'address' => [\n                    'name' => 'ANOTHER_NAME',\n                    'email' => 'ANOTHER_EMAIL',\n                ],\n            ],\n        ],\n        'bcc' => [\n            [\n                'address' => [\n                    'name' => 'AND_ANOTHER_NAME',\n                    'email' => 'AND_ANOTHER_EMAIL',\n                ],\n            ],\n        ],\n    ]);\n    } catch (\\Exception $error) {\n        var_dump($error);\n    }\nprint($response->getStatusCode());\n$results = $response->getBody()['results'];\nvar_dump($results);\n?>\n```\n\nMore examples [here](./examples/):\n### [Transmissions](./examples/transmissions/)\n- Create with attachment\n- Create with recipient list\n- Create with cc and bcc\n- Create with template\n- Create\n- Delete (scheduled transmission by campaign_id *only*)\n\n### [Templates](./examples/templates/)\n- Create\n- Get\n- Get (list) all\n- Update\n- Delete\n\n### [Message Events](./examples/message-events/)\n- get\n- get (with retry logic)\n\n### Send An API Call Using The Base Request Function\n\nWe provide a base request function to access any of our API resources.\n```php\n<?php\nrequire 'vendor/autoload.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n$sparky = new SparkPost($httpClient, [\n    'key' => getenv('SPARKPOST_API_KEY'),\n    'async' => false]);\n\n$webhookId = 'afd20f50-865a-11eb-ac38-6d7965d56459';\n$response = $sparky->request('DELETE', 'webhooks/' . $webhookId);\nprint($response->getStatusCode());\n?>\n```\n\n> Be sure to not have a leading `/` in your resource URI.\n\nFor complete list of resources, refer to [API documentation](https://developers.sparkpost.com/api/).\n\n## Handling Responses\nThe API calls either return a `SparkPostPromise` or `SparkPostResponse` depending on if `async` is `true` or `false`\n\n### Synchronous\n```php\n$sparky->setOptions(['async' => false]);\ntry {\n    $response = ... // YOUR API CALL GOES HERE\n\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n}\ncatch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n```\n\n### Asynchronous\nAsynchronous an be handled in two ways: by passing callbacks or waiting for the promise to be fulfilled. Waiting acts like synchronous request.\n##### Wait (Synchronous)\n```php\n\n$promise = ... // YOUR API CALL GOES HERE\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n\necho \"I will print out after the promise is fulfilled\";\n```\n\n##### Then (Asynchronous)\n```php\n$promise = ... // YOUR API CALL GOES HERE\n\n$promise->then(\n    // Success callback\n    function ($response) {\n        echo $response->getStatusCode().\"\\n\";\n        print_r($response->getBody()).\"\\n\";\n    },\n    // Failure callback\n    function (Exception $e) {\n        echo $e->getCode().\"\\n\";\n        echo $e->getMessage().\"\\n\";\n    }\n);\n\necho \"I will print out before the promise is fulfilled\";\n\n// You can combine multiple promises using \\GuzzleHttp\\Promise\\all() and other functions from the library.\n$promise->wait();\n```\n\n## Handling Exceptions\nAn exception will be thrown in two cases: there is a problem with the request or  the server returns a status code of `400` or higher.\n\n### SparkPostException\n* **getCode()**\n    * Returns the response status code of `400` or higher\n* **getMessage()**\n    * Returns the exception message\n* **getBody()**\n    * If there is a response body it returns it as an `Array`. Otherwise it returns `null`.\n* **getRequest()**\n    * Returns an array with the request values `method`, `url`, `headers`, `body` when `debug` is `true`\n\n\n### Contributing\nSee [contributing](https://github.com/SparkPost/php-sparkpost/blob/master/CONTRIBUTING.md).\n"
  },
  {
    "path": "composer.json",
    "content": "{\n  \"name\": \"sparkpost/sparkpost\",\n  \"description\": \"Client library for interfacing with the SparkPost API.\",\n  \"license\": \"MIT\",\n  \"authors\": [\n    {\n      \"name\": \"SparkPost\"\n    }\n  ],\n  \"minimum-stability\": \"stable\",\n  \"scripts\": {\n    \"test\": \"XDEBUG_MODE=coverage ./vendor/bin/phpunit\",\n    \"fix-style\": \"php-cs-fixer fix .\"\n  },\n  \"require\": {\n    \"php\": \"^7.1 || ^8.0\",\n    \"php-http/httplug\": \"^1.0 || ^2.0\",\n    \"php-http/message\": \"^1.0\",\n    \"php-http/client-implementation\": \"^1.0\",\n    \"php-http/discovery\": \"^1.0\"\n  },\n  \"require-dev\": {\n    \"phpunit/phpunit\": \"^8.0 || ^9.0\",\n    \"php-http/guzzle6-adapter\": \"^1.0\",\n    \"mockery/mockery\": \"^1.3\",\n    \"nyholm/nsa\": \"^1.0\",\n    \"php-coveralls/php-coveralls\": \"^2.4\",\n    \"friendsofphp/php-cs-fixer\": \"^2.18\"\n  },\n  \"autoload\": {\n    \"psr-4\": {\n      \"SparkPost\\\\\": \"lib/SparkPost\"\n    }\n  },\n  \"autoload-dev\": {\n    \"psr-4\": {\n      \"SparkPost\\\\Test\\\\\": \"test/unit\"\n    }\n  }\n}\n"
  },
  {
    "path": "examples/bootstrap.php",
    "content": "<?php\n\nrequire_once dirname(__FILE__).'/../vendor/autoload.php';\n"
  },
  {
    "path": "examples/debug/index.php",
    "content": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n/*\n * configure options in example-options.json\n */\n$sparky = new SparkPost($httpClient, [\n    \"key\" => getenv('SPARKPOST_API_KEY'),\n    // fetch API KEY from environment variable\n    \"debug\" => true\n]);\n\n$promise = $sparky->request('GET', 'templates');\n\ntry {\n    $response = $promise->wait();\n\n    var_dump($response);\n\n    echo \"Request:\\n\";\n    print_r($response->getRequest());\n\n    echo \"Response:\\n\";\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo \"Request:\\n\";\n    print_r($e->getRequest());\n\n    echo \"Exception:\\n\";\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/message-events/get_message_events.php",
    "content": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n// New endpoint - https://developers.sparkpost.com/api/events/\n$promise = $sparky->request('GET', 'events/message', [\n    'campaign_ids' => 'CAMPAIGN_ID',\n]);\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/message-events/get_message_events_with_retry_logic.php",
    "content": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY'), \"retries\" => 3]);\n\n// New endpoint - https://developers.sparkpost.com/api/events/\n$promise = $sparky->request('GET', 'events/message', [\n    'campaign_ids' => 'CAMPAIGN_ID',\n]);\n\n/**\n * If this fails with a 5xx it will have failed 4 times\n */\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n\n    if ($e->getCode() >= 500 && $e->getCode() <= 599) {\n        echo \"Wow, this failed epically\";\n    }\n}\n"
  },
  {
    "path": "examples/templates/create_template.php",
    "content": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n$template_name = \"PHP example template\";\n$template_id = \"PHP-example-template\";\n\n// put your own sending domain here\n$sending_domain = \"steve2-test.trymsys.net\";\n\n// Valid short template content examples\n$plain_text = 'Write your text message part here.';\n\n$html = <<<HTML\n<!DOCTYPE html>\n<html lang=\"en\">\n<body>\n  <p><strong>Write your HTML message part here</strong></p>\n</body>\n</html>\nHTML;\n\n$amp_html = <<<HTML\n<!doctype html>\n<html ⚡4email>\n<head>\n  <meta charset=\"utf-8\">\n  <style amp4email-boilerplate>body{visibility:hidden}</style>\n  <script async src=\"https://cdn.ampproject.org/v0.js\"></script>\n</head>\n<body>\nHello World! Let's get started using AMP HTML together!\n</body>\n</html>\nHTML;\n\n$promise = $sparky->request('POST', 'templates', [\n  'name' => $template_name,\n  'id' => $template_id,\n  'content' => [\n    'from' => \"from@$sending_domain\",\n    'subject' => 'Your Subject',\n    'text' => $plain_text,\n    'html' => $html,\n    'amp_html' => $amp_html,\n  ],\n]);\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/templates/delete_template.php",
    "content": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n$template_id = \"PHP-example-template\";\n\n$promise = $sparky->request('DELETE', \"templates/$template_id\");\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/templates/get_all_templates.php",
    "content": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n$promise = $sparky->request('GET', 'templates');\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/templates/get_template.php",
    "content": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n$template_id = \"PHP-example-template\";\n\n$promise = $sparky->request('GET', \"templates/$template_id?draft=true\");\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/templates/preview_template.php",
    "content": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n$template_id = \"PHP-example-template\";\n\n$promise = $sparky->request('POST', \"templates/$template_id/preview?draft=true\", [\n    'substitution_data' => [\n        'some_key' => 'some_value',\n    ],\n]);\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/templates/update_template.php",
    "content": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n$template_id = \"PHP-example-template\";\n\n$promise = $sparky->request('PUT', \"templates/$template_id\", [\n    'options' => [\n        'open_tracking' => true,\n    ],\n]);\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/transmissions/create_transmission.php",
    "content": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n// put your own sending domain and test recipient address here\n$sending_domain = \"steve2-test.trymsys.net\";\n$your_email = \"bob@sink.sparkpostmail.com\";\n\n$promise = $sparky->transmissions->post([\n    'content' => [\n        'from' => [\n            'name' => 'SparkPost Team',\n            'email' => \"from@$sending_domain\",\n        ],\n        'subject' => 'First Mailing From PHP',\n        'html' => '<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent your very first mailing!</p></body></html>',\n        'text' => 'Congratulations, {{name}}! You just sent your very first mailing!',\n    ],\n    'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],\n    'recipients' => [\n        [\n            'address' => [\n                'name' => 'YOUR_NAME',\n                'email' => $your_email,\n            ],\n        ],\n    ],\n]);\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/transmissions/create_transmission_with_attachment.php",
    "content": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n$filePath = dirname(__FILE__).'/';\n$fileName = 'sparkpost.png';\n$fileType = mime_content_type($filePath.$fileName);\n$fileData = base64_encode(file_get_contents($filePath.$fileName));\n\n// put your own sending domain and test recipient address here\n$sending_domain = \"steve2-test.trymsys.net\";\n$your_email = \"bob@sink.sparkpostmail.com\";\n\n$promise = $sparky->transmissions->post([\n    'content' => [\n        'from' => [\n            'name' => 'SparkPost Team',\n            'email' => \"from@$sending_domain\",\n        ],\n        'subject' => 'Mailing With Attachment From PHP',\n        'html' => '<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent an email with an attachment!</p></body></html>',\n        'text' => 'Congratulations, {{name}}! You just sent an email with an attachment',\n        'attachments' => [\n            [\n                'name' => $fileName,\n                'type' => $fileType,\n                'data' => $fileData,\n            ],\n        ],\n    ],\n    'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],\n    'recipients' => [\n        [\n            'address' => [\n                'name' => 'YOUR_NAME',\n                'email' => $your_email,\n            ],\n        ],\n    ],\n]);\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/transmissions/create_transmission_with_cc_and_bcc.php",
    "content": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n// put your own sending domain and test recipient address here\n$sending_domain = \"steve2-test.trymsys.net\";\n$your_email = \"bob@sink.sparkpostmail.com\";\n$your_cc = \"alice@sink.sparkpostmail.com\";\n$your_bcc = \"charles@sink.sparkpostmail.com\";\n\n$promise = $sparky->transmissions->post([\n    'content' => [\n        'from' => [\n            'name' => 'SparkPost Team',\n            'email' => \"from@$sending_domain\",\n        ],\n        'subject' => 'Mailing With CC and BCC From PHP',\n        'html' => '<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent your very first mailing with CC and BCC recipients!</p></body></html>',\n        'text' => 'Congratulations, {{name}}! You just sent your very first mailing with CC and BCC recipients!',\n    ],\n    'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],\n    'recipients' => [\n        [\n            'address' => [\n                'name' => 'YOUR_NAME',\n                'email' => $your_email,\n            ],\n        ],\n    ],\n    'cc' => [\n        [\n            'address' => [\n                'name' => 'ANOTHER_NAME',\n                'email' => $your_cc,\n            ],\n        ],\n    ],\n    'bcc' => [\n        [\n            'address' => [\n                'name' => 'AND_ANOTHER_NAME',\n                'email' => $your_bcc,\n            ],\n        ],\n    ],\n]);\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/transmissions/create_transmission_with_recipient_list.php",
    "content": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n// put your own sending domain and test recipient address here\n$sending_domain = \"steve2-test.trymsys.net\";\n\n// The ID of a list in your SparkPost account\n$my_list = \"mylist1\";\n\n$promise = $sparky->transmissions->post([\n    'content' => [\n        'from' => [\n            'name' => 'SparkPost Team',\n            'email' => \"from@$sending_domain\",\n        ],\n        'subject' => 'Mailing With Recipient List From PHP',\n        'html' => '<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent an email to everyone on your recipient list!</p></body></html>',\n        'text' => 'Congratulations, {{name}}! You just sent an email to everyone on your recipient list!',\n    ],\n    'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],\n    'recipients' => ['list_id' => $my_list],\n]);\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/transmissions/create_transmission_with_template.php",
    "content": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n// put your own sending domain and test recipient address here\n$sending_domain = \"steve2-test.trymsys.net\";\n$your_email = \"bob@sink.sparkpostmail.com\";\n\n$template_id = \"PHP-example-template\";\n\n$promise = $sparky->transmissions->post([\n    'content' => ['template_id' => $template_id],\n    'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],\n    'recipients' => [\n        [\n            'address' => [\n                'name' => 'YOUR_NAME',\n                'email' => $your_email,\n            ],\n        ],\n    ],\n]);\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/transmissions/delete_transmission.php",
    "content": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse GuzzleHttp\\Client;\nuse Http\\Adapter\\Guzzle6\\Client as GuzzleAdapter;\n\n$httpClient = new GuzzleAdapter(new Client());\n\n// In these examples, fetch API key from environment variable\n$sparky = new SparkPost($httpClient, [\"key\" => getenv('SPARKPOST_API_KEY')]);\n\n// Delete *scheduled* transmissions (only) by *campaign ID* (only)\n// See https://developers.sparkpost.com/api/transmissions/#transmissions-delete-delete-a-scheduled-transmission\n\n$promise = $sparky->transmissions->delete('?campaign_id=white_christmas');\n\ntry {\n    $response = $promise->wait();\n    echo $response->getStatusCode().\"\\n\";\n    print_r($response->getBody()).\"\\n\";\n} catch (\\Exception $e) {\n    echo $e->getCode().\"\\n\";\n    echo $e->getMessage().\"\\n\";\n}\n"
  },
  {
    "path": "examples/transmissions/get_all_transmissions.php",
    "content": "<?php\n// Feature has been deprecated\n// See https://developers.sparkpost.com/api/transmissions/#transmissions-get-retrieve-a-scheduled-transmission"
  },
  {
    "path": "examples/transmissions/get_transmission.php",
    "content": "<?php\n// Feature has been deprecated\n// See https://developers.sparkpost.com/api/transmissions/#transmissions-get-retrieve-a-scheduled-transmission"
  },
  {
    "path": "lib/SparkPost/Resource.php",
    "content": "<?php\n\nnamespace SparkPost;\n\n/**\n * Class Resource.\n *\n * @deprecated Soft reservations placed on name Resource (as of PHP7)\n */\nclass Resource extends ResourceBase\n{\n}\n"
  },
  {
    "path": "lib/SparkPost/ResourceBase.php",
    "content": "<?php\n\nnamespace SparkPost;\n\n/**\n * Class ResourceBase.\n */\nclass ResourceBase\n{\n    /**\n     * SparkPost object used to make requests.\n     */\n    protected $sparkpost;\n\n    /**\n     * The api endpoint that gets prepended to all requests send through this resource.\n     */\n    protected $endpoint;\n\n    /**\n     * Sets up the Resource.\n     *\n     * @param SparkPost $sparkpost - the sparkpost instance that this resource is attached to\n     * @param string    $endpoint  - the endpoint that this resource wraps\n     */\n    public function __construct(SparkPost $sparkpost, $endpoint)\n    {\n        $this->sparkpost = $sparkpost;\n        $this->endpoint = $endpoint;\n    }\n\n    /**\n     * Sends get request to API at the set endpoint.\n     *\n     * @see SparkPost->request()\n     */\n    public function get($uri = '', $payload = [], $headers = [])\n    {\n        return $this->request('GET', $uri, $payload, $headers);\n    }\n\n    /**\n     * Sends put request to API at the set endpoint.\n     *\n     * @see SparkPost->request()\n     */\n    public function put($uri = '', $payload = [], $headers = [])\n    {\n        return $this->request('PUT', $uri, $payload, $headers);\n    }\n\n    /**\n     * Sends post request to API at the set endpoint.\n     *\n     * @see SparkPost->request()\n     */\n    public function post($payload = [], $headers = [])\n    {\n        return $this->request('POST', '', $payload, $headers);\n    }\n\n    /**\n     * Sends delete request to API at the set endpoint.\n     *\n     * @see SparkPost->request()\n     */\n    public function delete($uri = '', $payload = [], $headers = [])\n    {\n        return $this->request('DELETE', $uri, $payload, $headers);\n    }\n\n    /**\n     * Sends requests to SparkPost object to the resource endpoint.\n     *\n     * @see SparkPost->request()\n     *\n     * @return SparkPostPromise or SparkPostResponse depending on sync or async request\n     */\n    public function request($method = 'GET', $uri = '', $payload = [], $headers = [])\n    {\n        if (is_array($uri)) {\n            $headers = $payload;\n            $payload = $uri;\n            $uri = '';\n        }\n\n        $uri = $this->endpoint.'/'.$uri;\n\n        return $this->sparkpost->request($method, $uri, $payload, $headers);\n    }\n}\n"
  },
  {
    "path": "lib/SparkPost/SparkPost.php",
    "content": "<?php\n\nnamespace SparkPost;\n\nuse Http\\Client\\HttpClient;\nuse Http\\Client\\HttpAsyncClient;\nuse Http\\Discovery\\MessageFactoryDiscovery;\nuse Http\\Message\\RequestFactory;\nuse Psr\\Http\\Message\\RequestInterface;\n\nclass SparkPost\n{\n    /**\n     * @var string Library version, used for setting User-Agent\n     */\n    private $version = '2.3.0';\n\n    /**\n     * @var HttpClient|HttpAsyncClient used to make requests\n     */\n    private $httpClient;\n\n    /**\n     * @var RequestFactory\n     */\n    private $messageFactory;\n\n    /**\n     * @var array Options for requests\n     */\n    private $options;\n\n    /**\n     * Default options for requests that can be overridden with the setOptions function.\n     */\n    private static $defaultOptions = [\n        'host' => 'api.sparkpost.com',\n        'protocol' => 'https',\n        'port' => 443,\n        'key' => '',\n        'version' => 'v1',\n        'async' => true,\n        'debug' => false,\n        'retries' => 0\n    ];\n\n    /**\n     * @var Transmission Instance of Transmission class\n     */\n    public $transmissions;\n\n    /**\n     * Sets up the SparkPost instance.\n     *\n     * @param HttpClient $httpClient - An httplug client or adapter\n     * @param array      $options    - An array to overide default options or a string to be used as an API key\n     */\n    public function __construct($httpClient, array $options)\n    {\n        $this->setOptions($options);\n        $this->setHttpClient($httpClient);\n        $this->setupEndpoints();\n    }\n\n    /**\n     * Sends either sync or async request based on async option.\n     *\n     * @param string $method\n     * @param string $uri\n     * @param array  $payload - either used as the request body or url query params\n     * @param array  $headers\n     *\n     * @return SparkPostPromise|SparkPostResponse Promise or Response depending on sync or async request\n     */\n    public function request($method = 'GET', $uri = '', $payload = [], $headers = [])\n    {\n        if ($this->options['async'] === true) {\n            return $this->asyncRequest($method, $uri, $payload, $headers);\n        } else {\n            return $this->syncRequest($method, $uri, $payload, $headers);\n        }\n    }\n\n    /**\n     * Sends sync request to SparkPost API.\n     *\n     * @param string $method\n     * @param string $uri\n     * @param array  $payload\n     * @param array  $headers\n     *\n     * @return SparkPostResponse\n     *\n     * @throws SparkPostException\n     */\n    public function syncRequest($method = 'GET', $uri = '', $payload = [], $headers = [])\n    {\n        $requestValues = $this->buildRequestValues($method, $uri, $payload, $headers);\n        $request = call_user_func_array(array($this, 'buildRequestInstance'), $requestValues);\n\n        $retries = $this->options['retries'];\n        try {\n            if ($retries > 0) {\n              $resp = $this->syncReqWithRetry($request, $retries);\n            } else {\n              $resp = $this->httpClient->sendRequest($request);\n            }\n            return new SparkPostResponse($resp, $this->ifDebug($requestValues));\n        } catch (\\Exception $exception) {\n            throw new SparkPostException($exception, $this->ifDebug($requestValues));\n        }\n    }\n\n    private function syncReqWithRetry($request, $retries)\n    {\n        $resp = $this->httpClient->sendRequest($request);\n        $status = $resp->getStatusCode();\n        if ($status >= 500 && $status <= 599 && $retries > 0) {\n          return $this->syncReqWithRetry($request, $retries-1);\n        }\n        return $resp;\n    }\n\n    /**\n     * Sends async request to SparkPost API.\n     *\n     * @param string $method\n     * @param string $uri\n     * @param array  $payload\n     * @param array  $headers\n     *\n     * @return SparkPostPromise\n     */\n    public function asyncRequest($method = 'GET', $uri = '', $payload = [], $headers = [])\n    {\n        if ($this->httpClient instanceof HttpAsyncClient) {\n            $requestValues = $this->buildRequestValues($method, $uri, $payload, $headers);\n            $request = call_user_func_array(array($this, 'buildRequestInstance'), $requestValues);\n\n            $retries = $this->options['retries'];\n            if ($retries > 0) {\n                return new SparkPostPromise($this->asyncReqWithRetry($request, $retries), $this->ifDebug($requestValues));\n            } else {\n                return new SparkPostPromise($this->httpClient->sendAsyncRequest($request), $this->ifDebug($requestValues));\n            }\n        } else {\n            throw new \\Exception('Your http client does not support asynchronous requests. Please use a different client or use synchronous requests.');\n        }\n    }\n\n    private function asyncReqWithRetry($request, $retries)\n    {\n        return $this->httpClient->sendAsyncRequest($request)->then(function($response) use ($request, $retries) {\n            $status = $response->getStatusCode();\n            if ($status >= 500 && $status <= 599 && $retries > 0) {\n                return $this->asyncReqWithRetry($request, $retries-1);\n            }\n            return $response;\n        });\n    }\n\n    /**\n     * Builds request values from given params.\n     *\n     * @param string $method\n     * @param string $uri\n     * @param array  $payload\n     * @param array  $headers\n     *\n     * @return array $requestValues\n     */\n    public function buildRequestValues($method, $uri, $payload, $headers)\n    {\n        $method = trim(strtoupper($method));\n\n        if ($method === 'GET') {\n            $params = $payload;\n            $body = [];\n        } else {\n            $params = [];\n            $body = $payload;\n        }\n\n        $url = $this->getUrl($uri, $params);\n        $headers = $this->getHttpHeaders($headers);\n\n        // old form-feed workaround now removed\n        $body = json_encode($body);\n        return [\n            'method' => $method,\n            'url' => $url,\n            'headers' => $headers,\n            'body' => $body,\n        ];\n    }\n\n    /**\n     * Build RequestInterface from given params.\n     *\n     * @param array $requestValues\n     *\n     * @return RequestInterface\n     */\n    public function buildRequestInstance($method, $url, $headers, $body)\n    {\n        return $this->getMessageFactory()->createRequest($method, $url, $headers, $body);\n    }\n\n    /**\n     * Build RequestInterface from given params.\n     *\n     * @param array $requestValues\n     *\n     * @return RequestInterface\n     */\n    public function buildRequest($method, $uri, $payload, $headers)\n    {\n        $requestValues = $this->buildRequestValues($method, $uri, $payload, $headers);\n        return call_user_func_array(array($this, 'buildRequestInstance'), $requestValues);\n    }\n\n    /**\n     * Returns an array for the request headers.\n     *\n     * @param array $headers - any custom headers for the request\n     *\n     * @return array $headers - headers for the request\n     */\n    public function getHttpHeaders($headers = [])\n    {\n        $constantHeaders = [\n            'Authorization' => $this->options['key'],\n            'Content-Type' => 'application/json',\n            'User-Agent' => 'php-sparkpost/'.$this->version,\n        ];\n\n        foreach ($constantHeaders as $key => $value) {\n            $headers[$key] = $value;\n        }\n\n        return $headers;\n    }\n\n    /**\n     * Builds the request url from the options and given params.\n     *\n     * @param string $path   - the path in the url to hit\n     * @param array  $params - query parameters to be encoded into the url\n     *\n     * @return string $url - the url to send the desired request to\n     */\n    public function getUrl($path, $params = [])\n    {\n        $options = $this->options;\n\n        $paramsArray = [];\n        foreach ($params as $key => $value) {\n            if (is_array($value)) {\n                $value = implode(',', $value);\n            }\n\n            array_push($paramsArray, $key.'='.$value);\n        }\n\n        $paramsString = implode('&', $paramsArray);\n\n        return $options['protocol'].'://'.$options['host'].($options['port'] ? ':'.$options['port'] : '').'/api/'.$options['version'].'/'.$path.($paramsString ? '?'.$paramsString : '');\n    }\n\n    /**\n     * Sets $httpClient to be used for request.\n     *\n     * @param HttpClient|HttpAsyncClient $httpClient - the client to be used for request\n     *\n     * @return SparkPost\n     */\n    public function setHttpClient($httpClient)\n    {\n        if (!($httpClient instanceof HttpAsyncClient || $httpClient instanceof HttpClient)) {\n            throw new \\LogicException(sprintf('Parameter to SparkPost::setHttpClient must be instance of \"%s\" or \"%s\"', HttpClient::class, HttpAsyncClient::class));\n        }\n\n        $this->httpClient = $httpClient;\n\n        return $this;\n    }\n\n    /**\n     * Sets the options from the param and defaults for the SparkPost object.\n     *\n     * @param array $options - either an string API key or an array of options\n     *\n     * @return SparkPost\n     */\n    public function setOptions($options)\n    {\n        // if the options map is a string we should assume that its an api key\n        if (is_string($options)) {\n            $options = ['key' => $options];\n        }\n\n        // Validate API key because its required\n        if (!isset($this->options['key']) && (!isset($options['key']) || !preg_match('/\\S/', $options['key']))) {\n            throw new \\Exception('You must provide an API key');\n        }\n\n        $this->options = isset($this->options) ? $this->options : self::$defaultOptions;\n\n        // set options, overriding defaults\n        foreach ($options as $option => $value) {\n            if (key_exists($option, $this->options)) {\n                $this->options[$option] = $value;\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Returns the given value if debugging, an empty instance otherwise.\n     *\n     * @param any $param\n     *\n     * @return any $param\n     */\n    private function ifDebug($param)\n    {\n        return $this->options['debug'] ? $param : null;\n    }\n\n    /**\n     * Sets up any endpoints to custom classes e.g. $this->transmissions.\n     */\n    private function setupEndpoints()\n    {\n        $this->transmissions = new Transmission($this);\n    }\n\n    /**\n     * @return RequestFactory\n     */\n    private function getMessageFactory()\n    {\n        if (!$this->messageFactory) {\n            $this->messageFactory = MessageFactoryDiscovery::find();\n        }\n\n        return $this->messageFactory;\n    }\n\n    /**\n     * @param RequestFactory $messageFactory\n     *\n     * @return SparkPost\n     */\n    public function setMessageFactory(RequestFactory $messageFactory)\n    {\n        $this->messageFactory = $messageFactory;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "lib/SparkPost/SparkPostException.php",
    "content": "<?php\n\nnamespace SparkPost;\n\nuse Http\\Client\\Exception\\HttpException as HttpException;\n\nclass SparkPostException extends \\Exception\n{\n    /**\n     * Variable to hold json decoded body from http response.\n     */\n    private $body = null;\n\n    /**\n     * Array with the request values sent.\n     */\n    private $request;\n\n    /**\n     * Sets up the custom exception and copies over original exception values.\n     *\n     * @param Exception $exception - the exception to be wrapped\n     */\n    public function __construct(\\Exception $exception, $request = null)\n    {\n        $this->request = $request;\n\n        $message = $exception->getMessage();\n        $code = $exception->getCode();\n        if ($exception instanceof HttpException) {\n            $message = $exception->getResponse()->getBody()->__toString();\n            $this->body = json_decode($message, true);\n            $code = $exception->getResponse()->getStatusCode();\n        }\n\n        parent::__construct($message, $code, $exception->getPrevious());\n    }\n\n    /**\n     * Returns the request values sent.\n     *\n     * @return array $request\n     */\n    public function getRequest()\n    {\n        return $this->request;\n    }\n\n    /**\n     * Returns the body.\n     *\n     * @return array $body - the json decoded body from the http response\n     */\n    public function getBody()\n    {\n        return $this->body;\n    }\n}\n"
  },
  {
    "path": "lib/SparkPost/SparkPostPromise.php",
    "content": "<?php\n\nnamespace SparkPost;\n\nuse Http\\Promise\\Promise as HttpPromise;\n\nclass SparkPostPromise implements HttpPromise\n{\n    /**\n     * HttpPromise to be wrapped by SparkPostPromise.\n     */\n    private $promise;\n\n    /**\n     * Array with the request values sent.\n     */\n    private $request;\n\n    /**\n     * set the promise to be wrapped.\n     *\n     * @param HttpPromise $promise\n     */\n    public function __construct(HttpPromise $promise, $request = null)\n    {\n        $this->promise = $promise;\n        $this->request = $request;\n    }\n\n    /**\n     * Hand off the response functions to the original promise and return a custom response or exception.\n     *\n     * @param callable $onFulfilled - function to be called if the promise is fulfilled\n     * @param callable $onRejected  - function to be called if the promise is rejected\n     */\n    public function then(callable $onFulfilled = null, callable $onRejected = null)\n    {\n        $request = $this->request;\n\n        return $this->promise->then(function ($response) use ($onFulfilled, $request) {\n            if (isset($onFulfilled)) {\n                $onFulfilled(new SparkPostResponse($response, $request));\n            }\n        }, function ($exception) use ($onRejected, $request) {\n            if (isset($onRejected)) {\n                $onRejected(new SparkPostException($exception, $request));\n            }\n        });\n    }\n\n    /**\n     * Hand back the state.\n     *\n     * @return $state - returns the state of the promise\n     */\n    public function getState()\n    {\n        return $this->promise->getState();\n    }\n\n    /**\n     * Wraps the wait function and returns a custom response or throws a custom exception.\n     *\n     * @param bool $unwrap\n     *\n     * @return SparkPostResponse\n     *\n     * @throws SparkPostException\n     */\n    public function wait($unwrap = true)\n    {\n        try {\n            $response = $this->promise->wait($unwrap);\n\n            return $response ? new SparkPostResponse($response, $this->request) : $response;\n        } catch (\\Exception $exception) {\n            throw new SparkPostException($exception, $this->request);\n        }\n    }\n}\n"
  },
  {
    "path": "lib/SparkPost/SparkPostResponse.php",
    "content": "<?php\n\nnamespace SparkPost;\n\nuse Psr\\Http\\Message\\ResponseInterface as ResponseInterface;\nuse Psr\\Http\\Message\\StreamInterface as StreamInterface;\n\nclass SparkPostResponse implements ResponseInterface\n{\n    /**\n     * ResponseInterface to be wrapped by SparkPostResponse.\n     */\n    private $response;\n\n    /**\n     * Array with the request values sent.\n     */\n    private $request;\n\n    /**\n     * set the response to be wrapped.\n     *\n     * @param ResponseInterface $response\n     */\n    public function __construct(ResponseInterface $response, $request = null)\n    {\n        $this->response = $response;\n        $this->request = $request;\n    }\n\n    /**\n     * Returns the request values sent.\n     *\n     * @return array $request\n     */\n    public function getRequest()\n    {\n        return $this->request;\n    }\n\n    /**\n     * Returns the body.\n     *\n     * @return array $body - the json decoded body from the http response\n     */\n    public function getBody()\n    {\n        $body = $this->response->getBody();\n        $body_string = $body->__toString();\n\n        $json = json_decode($body_string, true);\n\n        return $json;\n    }\n\n    /**\n     * pass these down to the response given in the constructor.\n     */\n    public function getProtocolVersion()\n    {\n        return $this->response->getProtocolVersion();\n    }\n\n    public function withProtocolVersion($version)\n    {\n        return $this->response->withProtocolVersion($version);\n    }\n\n    public function getHeaders()\n    {\n        return $this->response->getHeaders();\n    }\n\n    public function hasHeader($name)\n    {\n        return $this->response->hasHeader($name);\n    }\n\n    public function getHeader($name)\n    {\n        return $this->response->getHeader($name);\n    }\n\n    public function getHeaderLine($name)\n    {\n        return $this->response->getHeaderLine($name);\n    }\n\n    public function withHeader($name, $value)\n    {\n        return $this->response->withHeader($name, $value);\n    }\n\n    public function withAddedHeader($name, $value)\n    {\n        return $this->response->withAddedHeader($name, $value);\n    }\n\n    public function withoutHeader($name)\n    {\n        return $this->response->withoutHeader($name);\n    }\n\n    public function withBody(StreamInterface $body)\n    {\n        return $this->response->withBody($body);\n    }\n\n    public function getStatusCode()\n    {\n        return $this->response->getStatusCode();\n    }\n\n    public function withStatus($code, $reasonPhrase = '')\n    {\n        return $this->response->withStatus($code, $reasonPhrase);\n    }\n\n    public function getReasonPhrase()\n    {\n        return $this->response->getReasonPhrase();\n    }\n}\n"
  },
  {
    "path": "lib/SparkPost/Transmission.php",
    "content": "<?php\n\nnamespace SparkPost;\n\nclass Transmission extends ResourceBase\n{\n    public function __construct(SparkPost $sparkpost)\n    {\n        parent::__construct($sparkpost, 'transmissions');\n    }\n\n    /**\n     * Send post request to transmission endpoint after formatting cc, bcc, and expanding the shorthand emails.\n     *\n     * @return SparkPostPromise or SparkPostResponse depending on sync or async request\n     */\n    public function post($payload = [], $headers = [])\n    {\n        if (isset($payload['recipients']) && !isset($payload['recipients']['list_id'])) {\n            $payload = $this->formatPayload($payload);\n        }\n\n        return parent::post($payload, $headers);\n    }\n\n    /**\n     * Runs the given payload through the formatting functions.\n     *\n     * @param array $payload - the request body\n     *\n     * @return array - the modified request body\n     */\n    public function formatPayload($payload)\n    {\n        $payload = $this->formatBlindCarbonCopy($payload); //Fixes BCCs into payload\n        $payload = $this->formatCarbonCopy($payload); //Fixes CCs into payload\n        $payload = $this->formatShorthandRecipients($payload); //Fixes shorthand recipients format\n\n        return $payload;\n    }\n\n    /**\n     * Formats bcc list into recipients list.\n     *\n     * @param array $payload - the request body\n     *\n     * @return array - the modified request body\n     */\n    private function formatBlindCarbonCopy($payload)\n    {\n\n        //If there's a list of BCC recipients, move them into the correct format\n        if (isset($payload['bcc'])) {\n            $payload = $this->addListToRecipients($payload, 'bcc');\n        }\n\n        return $payload;\n    }\n\n    /**\n     * Formats cc list into recipients list and adds the CC header to the content.\n     *\n     * @param array $payload - the request body\n     *\n     * @return array - the modified request body\n     */\n    private function formatCarbonCopy($payload)\n    {\n        if (isset($payload['cc'])) {\n            $ccAddresses = [];\n            for ($i = 0; $i < count($payload['cc']); ++$i) {\n                array_push($ccAddresses, $this->toAddressString($payload['cc'][$i]['address']));\n            }\n\n            // set up the content headers as either what it was before or an empty array\n            $payload['content']['headers'] = isset($payload['content']['headers']) ? $payload['content']['headers'] : [];\n            // add cc header\n            $payload['content']['headers']['CC'] = implode(',', $ccAddresses);\n\n            $payload = $this->addListToRecipients($payload, 'cc');\n        }\n\n        return $payload;\n    }\n\n    /**\n     * Formats all recipients into the long form of [ \"name\" => \"John\", \"email\" => \"john@exmmple.com\" ].\n     *\n     * @param array $payload - the request body\n     *\n     * @return array - the modified request body\n     */\n    private function formatShorthandRecipients($payload)\n    {\n        if (isset($payload['content']['from'])) {\n            $payload['content']['from'] = $this->toAddressObject($payload['content']['from']);\n        }\n\n        for ($i = 0; $i < count($payload['recipients']); ++$i) {\n            $payload['recipients'][$i]['address'] = $this->toAddressObject($payload['recipients'][$i]['address']);\n        }\n\n        return $payload;\n    }\n\n    /**\n     * Loops through the given listName in the payload and adds all the recipients to the recipients list after removing their names.\n     *\n     * @param array $payload  - the request body\n     * @param array $listName - the name of the array in the payload to be moved to the recipients list\n     *\n     * @return array - the modified request body\n     */\n    private function addListToRecipients($payload, $listName)\n    {\n        $originalAddress = $this->toAddressString($payload['recipients'][0]['address']);\n        foreach ($payload[$listName] as $recipient) {\n            $recipient['address'] = $this->toAddressObject($recipient['address']);\n            $recipient['address']['header_to'] = $originalAddress;\n\n            // remove name from address - name is only put in the header for cc and not at all for bcc\n            if (isset($recipient['address']['name'])) {\n                unset($recipient['address']['name']);\n            }\n\n            array_push($payload['recipients'], $recipient);\n        }\n\n        //Delete the original object from the payload.\n        unset($payload[$listName]);\n\n        return $payload;\n    }\n\n    /**\n     * Takes the shorthand form of an email address and converts it to the long form.\n     *\n     * @param $address - the shorthand form of an email address \"Name <Email address>\"\n     *\n     * @return array - the longhand form of an email address [ \"name\" => \"John\", \"email\" => \"john@exmmple.com\" ]\n     */\n    private function toAddressObject($address)\n    {\n        $formatted = $address;\n        if (is_string($formatted)) {\n            $formatted = [];\n\n            if ($this->isEmail($address)) {\n                $formatted['email'] = $address;\n            } elseif (preg_match('/\"?(.[^\"]*)?\"?\\s*<(.+)>/', $address, $matches)) {\n                $name = trim($matches[1]);\n                $formatted['name'] = $matches[1];\n                $formatted['email'] = $matches[2];\n            } else {\n                throw new \\Exception('Invalid address format: '.$address);\n            }\n        }\n\n        return $formatted;\n    }\n\n    /**\n     * Takes the longhand form of an email address and converts it to the shorthand form.\n     *\n     * @param $address - the longhand form of an email address [ \"name\" => \"John\", \"email\" => \"john@exmmple.com\" ]\n     * @param string - the shorthand form of an email address \"Name <Email address>\"\n     */\n    private function toAddressString($address)\n    {\n        // convert object to string\n        if (!is_string($address)) {\n            if (isset($address['name'])) {\n                $address = '\"'.$address['name'].'\" <'.$address['email'].'>';\n            } else {\n                $address = $address['email'];\n            }\n        }\n\n        return $address;\n    }\n\n    /**\n     * Checks if a string is an email.\n     *\n     * @param string $email - a string that might be an email address\n     * @param bool - true if the given string is an email\n     */\n    private function isEmail($email)\n    {\n        if (filter_var($email, FILTER_VALIDATE_EMAIL)) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" backupGlobals=\"false\" backupStaticAttributes=\"false\" bootstrap=\"vendor/autoload.php\" colors=\"true\" convertErrorsToExceptions=\"true\" convertNoticesToExceptions=\"true\" convertWarningsToExceptions=\"true\" processIsolation=\"false\" stopOnFailure=\"false\" xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/9.3/phpunit.xsd\">\n<coverage processUncoveredFiles=\"true\">\n    <include>\n        <directory suffix=\".php\">./lib</directory>\n    </include>\n    <report>\n        <clover outputFile=\"test/output/clover.xml\"/>\n        <html outputDirectory=\"test/output/report\" lowUpperBound=\"50\" highLowerBound=\"90\"/>\n    </report>\n</coverage>\n<testsuites>\n    <testsuite name=\"Unit tests\">\n        <directory suffix=\"Test.php\">./test/unit</directory>\n    </testsuite>\n</testsuites>\n\n</phpunit>\n"
  },
  {
    "path": "test/unit/SparkPostResponseTest.php",
    "content": "<?php\n\nnamespace SparkPost\\Test;\n\nuse PHPUnit\\Framework\\TestCase;\nuse SparkPost\\SparkPostResponse;\nuse Mockery;\n\nclass SparkPostResponseTest extends TestCase\n{\n    /** @var Mockery\\MockInterface|\\Psr\\Http\\Message\\ResponseInterface */\n    private $responseMock;\n    /** @var string */\n    private $returnValue;\n\n    public function setUp(): void\n    {\n        $this->returnValue = 'some_value_to_return';\n        $this->responseMock = Mockery::mock('Psr\\Http\\Message\\ResponseInterface');\n    }\n\n    public function testGetProtocolVersion()\n    {\n        $this->responseMock->shouldReceive('getProtocolVersion')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->getProtocolVersion(), $sparkpostResponse->getProtocolVersion());\n    }\n\n    public function testWithProtocolVersion()\n    {\n        $param = 'protocol version';\n\n        $this->responseMock->shouldReceive('withProtocolVersion')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->withProtocolVersion($param), $sparkpostResponse->withProtocolVersion($param));\n    }\n\n    public function testGetHeaders()\n    {\n        $this->responseMock->shouldReceive('getHeaders')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->getHeaders(), $sparkpostResponse->getHeaders());\n    }\n\n    public function testHasHeader()\n    {\n        $param = 'header';\n\n        $this->responseMock->shouldReceive('hasHeader')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->hasHeader($param), $sparkpostResponse->hasHeader($param));\n    }\n\n    public function testGetHeader()\n    {\n        $param = 'header';\n\n        $this->responseMock->shouldReceive('getHeader')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->getHeader($param), $sparkpostResponse->getHeader($param));\n    }\n\n    public function testGetHeaderLine()\n    {\n        $param = 'header';\n\n        $this->responseMock->shouldReceive('getHeaderLine')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->getHeaderLine($param), $sparkpostResponse->getHeaderLine($param));\n    }\n\n    public function testWithHeader()\n    {\n        $param = 'header';\n        $param2 = 'value';\n\n        $this->responseMock->shouldReceive('withHeader')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->withHeader($param, $param2), $sparkpostResponse->withHeader($param, $param2));\n    }\n\n    public function testWithAddedHeader()\n    {\n        $param = 'header';\n        $param2 = 'value';\n\n        $this->responseMock->shouldReceive('withAddedHeader')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->withAddedHeader($param, $param2), $sparkpostResponse->withAddedHeader($param, $param2));\n    }\n\n    public function testWithoutHeader()\n    {\n        $param = 'header';\n\n        $this->responseMock->shouldReceive('withoutHeader')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->withoutHeader($param), $sparkpostResponse->withoutHeader($param));\n    }\n\n    public function testGetRequest()\n    {\n        $request = ['some' => 'request'];\n        $this->responseMock->shouldReceive('getRequest')->andReturn($request);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock, $request);\n        $this->assertEquals($sparkpostResponse->getRequest(), $request);\n    }\n\n    public function testWithBody()\n    {\n        $param = Mockery::mock('Psr\\Http\\Message\\StreamInterface');\n\n        $this->responseMock->shouldReceive('withBody')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->withBody($param), $sparkpostResponse->withBody($param));\n    }\n\n    public function testGetStatusCode()\n    {\n        $this->responseMock->shouldReceive('getStatusCode')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->getStatusCode(), $sparkpostResponse->getStatusCode());\n    }\n\n    public function testWithStatus()\n    {\n        $param = 'status';\n\n        $this->responseMock->shouldReceive('withStatus')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->withStatus($param), $sparkpostResponse->withStatus($param));\n    }\n\n    public function testGetReasonPhrase()\n    {\n        $this->responseMock->shouldReceive('getReasonPhrase')->andReturn($this->returnValue);\n        $sparkpostResponse = new SparkPostResponse($this->responseMock);\n        $this->assertEquals($this->responseMock->getReasonPhrase(), $sparkpostResponse->getReasonPhrase());\n    }\n}\n"
  },
  {
    "path": "test/unit/SparkPostTest.php",
    "content": "<?php\n\nnamespace SparkPost\\Test;\n\nuse Http\\Client\\HttpAsyncClient;\nuse Http\\Client\\HttpClient;\nuse Http\\Message\\MessageFactory;\nuse Nyholm\\NSA;\nuse PHPUnit\\Framework\\TestCase;\nuse SparkPost\\SparkPost;\nuse SparkPost\\SparkPostPromise;\nuse GuzzleHttp\\Promise\\FulfilledPromise as GuzzleFulfilledPromise;\nuse GuzzleHttp\\Promise\\RejectedPromise as GuzzleRejectedPromise;\nuse Http\\Adapter\\Guzzle6\\Promise as GuzzleAdapterPromise;\nuse Mockery;\n\nclass SparkPostTest extends TestCase\n{\n    private $clientMock;\n    /** @var SparkPost */\n    private $resource;\n\n    private $exceptionMock;\n    private $exceptionBody;\n\n    private $responseMock;\n    private $responseBody;\n\n    private $promiseMock;\n\n    private $postTransmissionPayload = [\n        'content' => [\n            'from' => ['name' => 'Sparkpost Team', 'email' => 'postmaster@sendmailfor.me'],\n            'subject' => 'First Mailing From PHP',\n            'text' => 'Congratulations, {{name}}!! You just sent your very first mailing!',\n        ],\n        'substitution_data' => ['name' => 'Avi'],\n        'recipients' => [\n            ['address' => 'avi.goldman@sparkpost.com'],\n        ],\n    ];\n\n    private $getTransmissionPayload = [\n        'campaign_id' => 'thanksgiving',\n    ];\n\n    public function setUp(): void\n    {\n        // response mock up\n        $responseBodyMock = Mockery::mock();\n        $this->responseBody = ['results' => 'yay'];\n        $this->responseMock = Mockery::mock('Psr\\Http\\Message\\ResponseInterface');\n        $this->responseMock->shouldReceive('getStatusCode')->andReturn(200);\n        $this->responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);\n        $responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($this->responseBody));\n\n        $errorBodyMock = Mockery::mock();\n        $this->badResponseBody = ['errors' => []];\n        $this->badResponseMock = Mockery::mock('Psr\\Http\\Message\\ResponseInterface');\n        $this->badResponseMock->shouldReceive('getStatusCode')->andReturn(503);\n        $this->badResponseMock->shouldReceive('getBody')->andReturn($errorBodyMock);\n        $errorBodyMock->shouldReceive('__toString')->andReturn(json_encode($this->badResponseBody));\n\n        // exception mock up\n        $exceptionResponseMock = Mockery::mock();\n        $this->exceptionBody = ['results' => 'failed'];\n        $this->exceptionMock = Mockery::mock('Http\\Client\\Exception\\HttpException');\n        $this->exceptionMock->shouldReceive('getResponse')->andReturn($exceptionResponseMock);\n        $exceptionResponseMock->shouldReceive('getStatusCode')->andReturn(500);\n        $exceptionResponseMock->shouldReceive('getBody->__toString')->andReturn(json_encode($this->exceptionBody));\n\n        // promise mock up\n        $this->promiseMock = Mockery::mock('Http\\Promise\\Promise');\n\n        //setup mock for the adapter\n        $this->clientMock = Mockery::mock('Http\\Adapter\\Guzzle6\\Client');\n        $this->clientMock->shouldReceive('sendAsyncRequest')->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andReturn($this->promiseMock);\n\n        $this->resource = new SparkPost($this->clientMock, ['key' => 'SPARKPOST_API_KEY']);\n    }\n\n    public function tearDown(): void\n    {\n        Mockery::close();\n    }\n\n    public function testRequestSync()\n    {\n        $this->resource->setOptions(['async' => false]);\n        $this->clientMock->shouldReceive('sendRequest')->andReturn($this->responseMock);\n\n        $this->assertInstanceOf('SparkPost\\SparkPostResponse', $this->resource->request('POST', 'transmissions', $this->postTransmissionPayload));\n    }\n\n    public function testRequestAsync()\n    {\n        $promiseMock = Mockery::mock('Http\\Promise\\Promise');\n        $this->resource->setOptions(['async' => true]);\n        $this->clientMock->shouldReceive('sendAsyncRequest')->andReturn($promiseMock);\n\n        $this->assertInstanceOf('SparkPost\\SparkPostPromise', $this->resource->request('GET', 'transmissions', $this->getTransmissionPayload));\n    }\n\n    public function testDebugOptionWhenFalse() {\n        $this->resource->setOptions(['async' => false, 'debug' => false]);\n        $this->clientMock->shouldReceive('sendRequest')->andReturn($this->responseMock);\n\n        $response = $this->resource->request('POST', 'transmissions', $this->postTransmissionPayload);\n\n        $this->assertEquals($response->getRequest(), null);\n    }\n\n    public function testDebugOptionWhenTrue() {\n        // setup\n        $this->resource->setOptions(['async' => false, 'debug' => true]);\n\n        // successful\n        $this->clientMock->shouldReceive('sendRequest')->once()->andReturn($this->responseMock);\n        $response = $this->resource->request('POST', 'transmissions', $this->postTransmissionPayload);\n        $this->assertEquals(json_decode($response->getRequest()['body'], true), $this->postTransmissionPayload);\n\n        // unsuccessful\n        $this->clientMock->shouldReceive('sendRequest')->once()->andThrow($this->exceptionMock);\n\n        try {\n            $response = $this->resource->request('POST', 'transmissions', $this->postTransmissionPayload);\n        }\n        catch (\\Exception $e) {\n            $this->assertEquals(json_decode($e->getRequest()['body'], true), $this->postTransmissionPayload);\n        }\n    }\n\n    public function testSuccessfulSyncRequest()\n    {\n        $this->clientMock->shouldReceive('sendRequest')->\n            once()->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andReturn($this->responseMock);\n\n        $response = $this->resource->syncRequest('POST', 'transmissions', $this->postTransmissionPayload);\n\n        $this->assertEquals($this->responseBody, $response->getBody());\n        $this->assertEquals(200, $response->getStatusCode());\n    }\n\n    public function testUnsuccessfulSyncRequest()\n    {\n        $this->clientMock->shouldReceive('sendRequest')->\n            once()->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andThrow($this->exceptionMock);\n\n        try {\n            $this->resource->syncRequest('POST', 'transmissions', $this->postTransmissionPayload);\n        } catch (\\Exception $e) {\n            $this->assertEquals($this->exceptionBody, $e->getBody());\n            $this->assertEquals(500, $e->getCode());\n        }\n    }\n\n    public function testSuccessfulSyncRequestWithRetries()\n    {\n        $this->clientMock->shouldReceive('sendRequest')->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andReturn($this->badResponseMock, $this->badResponseMock, $this->responseMock);\n\n        $this->resource->setOptions(['retries' => 2]);\n        $response = $this->resource->syncRequest('POST', 'transmissions', $this->postTransmissionPayload);\n\n        $this->assertEquals($this->responseBody, $response->getBody());\n        $this->assertEquals(200, $response->getStatusCode());\n    }\n\n    public function testUnsuccessfulSyncRequestWithRetries()\n    {\n        $this->clientMock->shouldReceive('sendRequest')->\n            once()->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andThrow($this->exceptionMock);\n\n        $this->resource->setOptions(['retries' => 2]);\n        try {\n            $this->resource->syncRequest('POST', 'transmissions', $this->postTransmissionPayload);\n        } catch (\\Exception $e) {\n            $this->assertEquals($this->exceptionBody, $e->getBody());\n            $this->assertEquals(500, $e->getCode());\n        }\n    }\n\n    public function testSuccessfulAsyncRequestWithWait()\n    {\n        $this->promiseMock->shouldReceive('wait')->andReturn($this->responseMock);\n\n        $promise = $this->resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);\n        $response = $promise->wait();\n\n        $this->assertEquals($this->responseBody, $response->getBody());\n        $this->assertEquals(200, $response->getStatusCode());\n    }\n\n    public function testUnsuccessfulAsyncRequestWithWait()\n    {\n        $this->promiseMock->shouldReceive('wait')->andThrow($this->exceptionMock);\n\n        $promise = $this->resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);\n\n        try {\n            $response = $promise->wait();\n        } catch (\\Exception $e) {\n            $this->assertEquals($this->exceptionBody, $e->getBody());\n            $this->assertEquals(500, $e->getCode());\n        }\n    }\n\n    public function testSuccessfulAsyncRequestWithThen()\n    {\n        $guzzlePromise = new GuzzleFulfilledPromise($this->responseMock);\n        $result = $this->resource->buildRequest('POST', 'transmissions', $this->postTransmissionPayload, []);\n\n        $promise = new SparkPostPromise(new GuzzleAdapterPromise($guzzlePromise, $result));\n\n        $responseBody = $this->responseBody;\n        $promise->then(function ($response) use ($responseBody) {\n            $this->assertEquals(200, $response->getStatusCode());\n            $this->assertEquals($responseBody, $response->getBody());\n        }, null)->wait();\n    }\n\n    public function testUnsuccessfulAsyncRequestWithThen()\n    {\n        $guzzlePromise = new GuzzleRejectedPromise($this->exceptionMock);\n        $result = $this->resource->buildRequest('POST', 'transmissions', $this->postTransmissionPayload, []);\n\n        $promise = new SparkPostPromise(new GuzzleAdapterPromise($guzzlePromise, $result));\n\n        $exceptionBody = $this->exceptionBody;\n        $promise->then(null, function ($exception) use ($exceptionBody) {\n            $this->assertEquals(500, $exception->getCode());\n            $this->assertEquals($exceptionBody, $exception->getBody());\n        })->wait();\n    }\n\n    public function testSuccessfulAsyncRequestWithRetries()\n    {\n        $testReq = $this->resource->buildRequest('POST', 'transmissions', $this->postTransmissionPayload, []);\n        $clientMock = Mockery::mock('Http\\Adapter\\Guzzle6\\Client');\n        $clientMock->shouldReceive('sendAsyncRequest')->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andReturn(\n                new GuzzleAdapterPromise(new GuzzleFulfilledPromise($this->badResponseMock), $testReq),\n                new GuzzleAdapterPromise(new GuzzleFulfilledPromise($this->badResponseMock), $testReq),\n                new GuzzleAdapterPromise(new GuzzleFulfilledPromise($this->responseMock), $testReq)\n            );\n\n        $resource = new SparkPost($clientMock, ['key' => 'SPARKPOST_API_KEY']);\n\n        $resource->setOptions(['async' => true, 'retries' => 2]);\n        $promise = $resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);\n        $promise->then(function($resp) {\n            $this->assertEquals(200, $resp->getStatusCode());\n        })->wait();\n    }\n\n    public function testUnsuccessfulAsyncRequestWithRetries()\n    {\n        $testReq = $this->resource->buildRequest('POST', 'transmissions', $this->postTransmissionPayload, []);\n        $rejectedPromise = new GuzzleRejectedPromise($this->exceptionMock);\n        $clientMock = Mockery::mock('Http\\Adapter\\Guzzle6\\Client');\n        $clientMock->shouldReceive('sendAsyncRequest')->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andReturn(new GuzzleAdapterPromise($rejectedPromise, $testReq));\n\n        $resource = new SparkPost($clientMock, ['key' => 'SPARKPOST_API_KEY']);\n\n        $resource->setOptions(['async' => true, 'retries' => 2]);\n        $promise = $resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);\n        $promise->then(null, function($exception) {\n            $this->assertEquals(500, $exception->getCode());\n            $this->assertEquals($this->exceptionBody, $exception->getBody());\n        })->wait();\n    }\n\n    public function testPromise()\n    {\n        $promise = $this->resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);\n\n        $this->promiseMock->shouldReceive('getState')->twice()->andReturn('pending');\n        $this->assertEquals($this->promiseMock->getState(), $promise->getState());\n\n        $this->promiseMock->shouldReceive('getState')->twice()->andReturn('rejected');\n        $this->assertEquals($this->promiseMock->getState(), $promise->getState());\n    }\n\n    public function testUnsupportedAsyncRequest()\n    {\n        $this->expectException(\\Exception::class);\n\n        $this->resource->setHttpClient(Mockery::mock('Http\\Client\\HttpClient'));\n\n        $this->resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);\n    }\n\n    public function testGetHttpHeaders()\n    {\n        $headers = $this->resource->getHttpHeaders([\n            'Custom-Header' => 'testing',\n        ]);\n\n        $version = NSA::getProperty($this->resource, 'version');\n\n        $this->assertEquals('SPARKPOST_API_KEY', $headers['Authorization']);\n        $this->assertEquals('application/json', $headers['Content-Type']);\n        $this->assertEquals('testing', $headers['Custom-Header']);\n        $this->assertEquals('php-sparkpost/'.$version, $headers['User-Agent']);\n    }\n\n    public function testGetUrl()\n    {\n        $url = 'https://api.sparkpost.com:443/api/v1/transmissions?key=value 1,value 2,value 3';\n        $testUrl = $this->resource->getUrl('transmissions', ['key' => ['value 1', 'value 2', 'value 3']]);\n        $this->assertEquals($url, $testUrl);\n    }\n\n    public function testSetHttpClient()\n    {\n        $mock = Mockery::mock(HttpClient::class);\n        $this->resource->setHttpClient($mock);\n        $this->assertEquals($mock, NSA::getProperty($this->resource, 'httpClient'));\n    }\n\n    public function testSetHttpAsyncClient()\n    {\n        $mock = Mockery::mock(HttpAsyncClient::class);\n        $this->resource->setHttpClient($mock);\n        $this->assertEquals($mock, NSA::getProperty($this->resource, 'httpClient'));\n    }\n\n    public function testSetHttpClientException()\n    {\n        $this->expectException(\\Exception::class);\n\n        $this->resource->setHttpClient(new \\stdClass());\n    }\n\n    public function testSetOptionsStringKey()\n    {\n        $this->resource->setOptions('SPARKPOST_API_KEY');\n        $options = NSA::getProperty($this->resource, 'options');\n        $this->assertEquals('SPARKPOST_API_KEY', $options['key']);\n    }\n\n    public function testSetBadOptions()\n    {\n        $this->expectException(\\Exception::class);\n\n        NSA::setProperty($this->resource, 'options', []);\n        $this->resource->setOptions(['not' => 'SPARKPOST_API_KEY']);\n    }\n\n    public function testSetMessageFactory()\n    {\n        $messageFactory = Mockery::mock(MessageFactory::class);\n        $this->resource->setMessageFactory($messageFactory);\n\n        $this->assertEquals($messageFactory, NSA::invokeMethod($this->resource, 'getMessageFactory'));\n    }\n}\n"
  },
  {
    "path": "test/unit/TransmissionTest.php",
    "content": "<?php\n\nnamespace SparkPost\\Test;\n\nuse PHPUnit\\Framework\\TestCase;\nuse SparkPost\\SparkPost;\nuse Mockery;\n\nclass TransmissionTest extends TestCase\n{\n    private $clientMock;\n    /** @var SparkPost */\n    private $resource;\n\n    private $postTransmissionPayload = [\n        'content' => [\n            'from' => ['name' => 'Sparkpost Team', 'email' => 'postmaster@sendmailfor.me'],\n            'subject' => 'First Mailing From PHP',\n            'text' => 'Congratulations, {{name}}!! You just sent your very first mailing!',\n        ],\n        'substitution_data' => ['name' => 'Avi'],\n        'recipients' => [\n            [\n                'address' => [\n                    'name' => 'Vincent',\n                    'email' => 'vincent.song@sparkpost.com',\n                ],\n            ],\n            ['address' => 'test@example.com'],\n        ],\n        'cc' => [\n            [\n                'address' => [\n                    'email' => 'avi.goldman@sparkpost.com',\n                ],\n            ],\n        ],\n        'bcc' => [\n            ['address' => 'Emely Giraldo <emely.giraldo@sparkpost.com>'],\n        ],\n\n    ];\n\n    private $getTransmissionPayload = [\n        'campaign_id' => 'thanksgiving',\n    ];\n\n    /**\n     * (non-PHPdoc).\n     *\n     * @before\n     *\n     * @see PHPUnit_Framework_TestCase::setUp()\n     */\n    public function setUp(): void\n    {\n        //setup mock for the adapter\n        $this->clientMock = Mockery::mock('Http\\Adapter\\Guzzle6\\Client');\n\n        $this->resource = new SparkPost($this->clientMock, ['key' => 'SPARKPOST_API_KEY', 'async' => false]);\n    }\n\n    public function tearDown(): void\n    {\n        Mockery::close();\n    }\n\n    public function testInvalidEmailFormat()\n    {\n        $this->expectException(\\Exception::class);\n\n        $this->postTransmissionPayload['recipients'][] = [\n            'address' => 'invalid email format',\n        ];\n\n        $response = $this->resource->transmissions->post($this->postTransmissionPayload);\n    }\n\n    public function testGet()\n    {\n        $responseMock = Mockery::mock('Psr\\Http\\Message\\ResponseInterface');\n        $responseBodyMock = Mockery::mock();\n\n        $responseBody = ['results' => 'yay'];\n\n        $this->clientMock->shouldReceive('sendRequest')->\n            once()->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andReturn($responseMock);\n\n        $responseMock->shouldReceive('getStatusCode')->andReturn(200);\n        $responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);\n        $responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($responseBody));\n\n        $response = $this->resource->transmissions->get($this->getTransmissionPayload);\n\n        $this->assertEquals($responseBody, $response->getBody());\n        $this->assertEquals(200, $response->getStatusCode());\n    }\n\n    public function testPut()\n    {\n        $responseMock = Mockery::mock('Psr\\Http\\Message\\ResponseInterface');\n        $responseBodyMock = Mockery::mock();\n\n        $responseBody = ['results' => 'yay'];\n\n        $this->clientMock->shouldReceive('sendRequest')->\n            once()->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andReturn($responseMock);\n\n        $responseMock->shouldReceive('getStatusCode')->andReturn(200);\n        $responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);\n        $responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($responseBody));\n\n        $response = $this->resource->transmissions->put($this->getTransmissionPayload);\n\n        $this->assertEquals($responseBody, $response->getBody());\n        $this->assertEquals(200, $response->getStatusCode());\n    }\n\n    public function testPost()\n    {\n        $responseMock = Mockery::mock('Psr\\Http\\Message\\ResponseInterface');\n        $responseBodyMock = Mockery::mock();\n\n        $responseBody = ['results' => 'yay'];\n\n        $this->clientMock->shouldReceive('sendRequest')->\n            once()->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andReturn($responseMock);\n\n        $responseMock->shouldReceive('getStatusCode')->andReturn(200);\n        $responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);\n        $responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($responseBody));\n\n        $response = $this->resource->transmissions->post($this->postTransmissionPayload);\n\n        $this->assertEquals($responseBody, $response->getBody());\n        $this->assertEquals(200, $response->getStatusCode());\n    }\n\n    public function testPostWithRecipientList()\n    {\n        $postTransmissionPayload = $this->postTransmissionPayload;\n        $postTransmissionPayload['recipients'] = ['list_id' => 'SOME_LIST_ID'];\n\n        $responseMock = Mockery::mock('Psr\\Http\\Message\\ResponseInterface');\n        $responseBodyMock = Mockery::mock();\n\n        $responseBody = ['results' => 'yay'];\n\n        $this->clientMock->shouldReceive('sendRequest')->\n            once()->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andReturn($responseMock);\n\n        $responseMock->shouldReceive('getStatusCode')->andReturn(200);\n        $responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);\n        $responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($responseBody));\n\n        $response = $this->resource->transmissions->post();\n\n        $this->assertEquals($responseBody, $response->getBody());\n        $this->assertEquals(200, $response->getStatusCode());\n    }\n\n    public function testDelete()\n    {\n        $responseMock = Mockery::mock('Psr\\Http\\Message\\ResponseInterface');\n        $responseBodyMock = Mockery::mock();\n\n        $responseBody = ['results' => 'yay'];\n\n        $this->clientMock->shouldReceive('sendRequest')->\n            once()->\n            with(Mockery::type('GuzzleHttp\\Psr7\\Request'))->\n            andReturn($responseMock);\n\n        $responseMock->shouldReceive('getStatusCode')->andReturn(200);\n        $responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);\n        $responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($responseBody));\n\n        $response = $this->resource->transmissions->delete($this->getTransmissionPayload);\n\n        $this->assertEquals($responseBody, $response->getBody());\n        $this->assertEquals(200, $response->getStatusCode());\n    }\n\n    public function testFormatPayload()\n    {\n        $correctFormattedPayload = json_decode('{\"content\":{\"from\":{\"name\":\"Sparkpost Team\",\"email\":\"postmaster@sendmailfor.me\"},\"subject\":\"First Mailing From PHP\",\"text\":\"Congratulations, {{name}}!! You just sent your very first mailing!\",\"headers\":{\"CC\":\"avi.goldman@sparkpost.com\"}},\"substitution_data\":{\"name\":\"Avi\"},\"recipients\":[{\"address\":{\"name\":\"Vincent\",\"email\":\"vincent.song@sparkpost.com\"}},{\"address\":{\"email\":\"test@example.com\"}},{\"address\":{\"email\":\"emely.giraldo@sparkpost.com\",\"header_to\":\"\\\"Vincent\\\" <vincent.song@sparkpost.com>\"}},{\"address\":{\"email\":\"avi.goldman@sparkpost.com\",\"header_to\":\"\\\"Vincent\\\" <vincent.song@sparkpost.com>\"}}]}', true);\n\n        $formattedPayload = $this->resource->transmissions->formatPayload($this->postTransmissionPayload);\n        $this->assertEquals($correctFormattedPayload, $formattedPayload);\n    }\n}\n"
  }
]