Repository: SparkPost/php-sparkpost
Branch: master
Commit: 2c7f60d27afb
Files: 39
Total size: 98.4 KB
Directory structure:
gitextract_jlhy3dwi/
├── .coveralls.yml
├── .editorconfig
├── .travis.yml
├── AUTHORS.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── MIGRATION.md
├── README.md
├── composer.json
├── examples/
│ ├── bootstrap.php
│ ├── debug/
│ │ └── index.php
│ ├── message-events/
│ │ ├── get_message_events.php
│ │ └── get_message_events_with_retry_logic.php
│ ├── templates/
│ │ ├── create_template.php
│ │ ├── delete_template.php
│ │ ├── get_all_templates.php
│ │ ├── get_template.php
│ │ ├── preview_template.php
│ │ └── update_template.php
│ └── transmissions/
│ ├── create_transmission.php
│ ├── create_transmission_with_attachment.php
│ ├── create_transmission_with_cc_and_bcc.php
│ ├── create_transmission_with_recipient_list.php
│ ├── create_transmission_with_template.php
│ ├── delete_transmission.php
│ ├── get_all_transmissions.php
│ └── get_transmission.php
├── lib/
│ └── SparkPost/
│ ├── Resource.php
│ ├── ResourceBase.php
│ ├── SparkPost.php
│ ├── SparkPostException.php
│ ├── SparkPostPromise.php
│ ├── SparkPostResponse.php
│ └── Transmission.php
├── phpunit.xml.dist
└── test/
└── unit/
├── SparkPostResponseTest.php
├── SparkPostTest.php
└── TransmissionTest.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .coveralls.yml
================================================
# single file
coverage_clover: test/output/clover.xml
json_path: test/output/coveralls-upload.json
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.yml]
indent_style = space
indent_size = 2
================================================
FILE: .travis.yml
================================================
language: php
php:
- '7.2'
- '7.3'
- '7.4'
- '8.0'
install:
- composer install --no-interaction
script:
- mkdir -p test/output/report
- composer test
after_script:
- php vendor/bin/php-coveralls
notifications:
slack:
secure: mw6HF2KR0YwYcIaYvV6qjuWC+XSIP8SQOe13VwmGf3b783hMcZDZTUS9N4bIfpwYi74A9qmzKdc425OSu45nceAf7hzFusCY5rYMoLQK/ksJ7sd+ay7tWhPRuomG1w8idTyXtzce23zOfBtOCHQakbavH2Uz6mh5lJYPFlMKW4c=
================================================
FILE: AUTHORS.md
================================================
php-sparkpost is maintained by Message Systems.
# Contributors
* Jordan Nornhold, [@beardyman](https://github.com/beardyman)
* Rich Leland, [@richleland](https://github.com/richleland)
* Jason Rhodes [@jasonrhodes](https://github.com/jasonrhodes)
* Matthew April, [@MattApril](https://github.com/MattApril)
* James Fellows, [@j4m3s](https://github.com/j4m3s)
* LF Bittencourt, [@lfbittencourt](https://github.com/lfbittencourt)
* Jakub Piasecki, [@zaporylie](https://github.com/zaporylie)
* Danil Zakablukovskiy, [@djagya](https://github.com/djagya)
* Chris Wilson, [@yepher](https://github.com/yepher)
* Maxim Dzhuliy, [@max-si-m](https://github.com/max-si-m)
* [@chandon](https://github.com/chandon)
* Avi Goldman, [@avrahamgoldman](https://github.com/avrahamgoldman)
* Vincent Song, [@vwsong](https://github.com/vwsong)
* Tobias Nyholm, [@Nyholm](https://github.com/Nyholm)
================================================
FILE: CHANGELOG.md
================================================
# Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased][unreleased]
## [2.3.0] - 2021-03-16
- [#201](https://github.com/SparkPost/php-sparkpost/pull/201) Update examples, README
- [#200](https://github.com/SparkPost/php-sparkpost/pull/200) PHP 8 support
## [2.2.1] - 2021-03-08
- [#198](https://github.com/SparkPost/php-sparkpost/pull/198) Address #197: No longer need formfeed replacement. README work.
- [#191](https://github.com/SparkPost/php-sparkpost/pull/191) Updating License
## [2.2.0] - 2019-06-04
- [#187](https://github.com/SparkPost/php-sparkpost/pull/187) Updated composer.json
- [#169](https://github.com/SparkPost/php-sparkpost/pull/169) Optional automatic retry on 5xx
- [#166](https://github.com/SparkPost/php-sparkpost/pull/166/files) Quick fix for using the API without composer
- [#149](https://github.com/SparkPost/php-sparkpost/pull/149) Setters should return current object
## [2.1.0] - 2017-01-09
### Added
- [#161](https://github.com/SparkPost/php-sparkpost/pull/161) added example for sending email with attachment and simplified the examples setup
- [#159](https://github.com/SparkPost/php-sparkpost/pull/159) added `debug` option for seeing the full request sent to SparkPost
- [#151](https://github.com/SparkPost/php-sparkpost/pull/151) added packagist badges
- [#139](https://github.com/SparkPost/php-sparkpost/pull/139) added examples for message events and templates
### Changed
- [#150](https://github.com/SparkPost/php-sparkpost/issues/150) renamed the `Resource` class to `ResourceBase` since resource soft reserved in php 7
- [#137](https://github.com/SparkPost/php-sparkpost/pull/137) cleaned up tests and post install scripts
- [#138](https://github.com/SparkPost/php-sparkpost/pull/138) added PHP 7.1 as a test environment
### Fixed
- [#156](https://github.com/SparkPost/php-sparkpost/pull/156) fixed typo in README.md
- [#152](https://github.com/SparkPost/php-sparkpost/issues/152) fixed propagation of coverage tests to coveralls.io
- [#147](https://github.com/SparkPost/php-sparkpost/pull/147) fixed examples in README.md
- [#139](https://github.com/SparkPost/php-sparkpost/pull/139) fixed the ability to send using recipient lists
- Issue[#141](https://github.com/SparkPost/php-sparkpost/issues/141) removed form feeds from the JSON body sent to the API
## [2.0.3] - 2016-07-28
### Fixed
- Issue [#135](https://github.com/SparkPost/php-sparkpost/issues/135) reported `Http\Discovery\NotFoundException` caused by 2.0.2 update.
## [2.0.2] - 2016-07-28
### Fixed
- [#131](https://github.com/SparkPost/php-sparkpost/pull/131) removed any dependency on Guzzle by replacing it with `MessageFactoryDiscovery`
## [2.0.1] - 2016-06-29
### Fixed
- [#129](https://github.com/SparkPost/php-sparkpost/pull/129) issue with `content.from` being expected even when using a stored template
## [2.0.0] - 2016-06-24
This 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.
### Changed
- [#123](https://github.com/SparkPost/php-sparkpost/pull/123) Rewrote docs and updated composer name
- [#122](https://github.com/SparkPost/php-sparkpost/pull/122) Add transmission class and examples
- [#121](https://github.com/SparkPost/php-sparkpost/pull/121) Update base resource and tests
## [1.2.1] - 2016-05-27
### Fixed
- [#111](https://github.com/SparkPost/php-sparkpost/pull/111) allow pass through of timeout setting in http config
## [1.2.0] - 2016-05-04
### Added
- [EditorConfig](http://editorconfig.org/) file to maintain consistent coding style
- `composer run-script fix-style` can now be run to enforce PSR-2 style
### Changed
- Responses from the SparkPost API with HTTP status code 403 now properly raise with message, code, and description
### Fixed
- Removed reliance on composer for version of library
## [1.1.0] - 2016-05-02
### Added
- Message Events API added.
### Changed
- Transmission API now accepts a DateTime object for startDate
## [1.0.3] - 2016-03-25
### Added
- Support for attachments, inline attachments, inline css, sandbox, start time, and transactional options in `Transmission` class
- API response exceptions now include message, code, and description from API
## [1.0.2] - 2016-02-28
### Fixed
- Miscellaneous code cleanups related to docs and namespacing
## [1.0.1] - 2016-02-24
### Added
- Example for using `setupUnwrapped()` to get a list of webhooks.
- CHANGELOG.md for logging release updates and backfilled it with previous release.
### Fixed
- Library will now throw a `SparkPost\APIReponseException` properly when a 4XX http status is encountered.
## 1.0.0 - 2015-10-15
### Added
- Request adapter interface for passing in request adapters via `Ivory\HttpAdapter`
- Ability to create 'unwrapped' modules for API endpoints that haven't had functionality included yet.
- Instructions for setting up request adapters in README
### Changed
- Library now requires PHP 5.5 or greater
- Updated interface to be instance based with referenceable objects rather than static functions.
### Fixed
- README now has proper code blocks denoting PHP language
[unreleased]: https://github.com/sparkpost/php-sparkpost/compare/2.2.1...HEAD
[2.2.1]: https://github.com/sparkpost/php-sparkpost/compare/2.2.0...2.2.1
[2.2.0]: https://github.com/sparkpost/php-sparkpost/compare/2.1.0...2.2.0
[2.1.0]: https://github.com/sparkpost/php-sparkpost/compare/2.0.3...2.1.0
[2.0.3]: https://github.com/sparkpost/php-sparkpost/compare/2.0.2...2.0.3
[2.0.2]: https://github.com/sparkpost/php-sparkpost/compare/2.0.1...2.0.2
[2.0.1]: https://github.com/sparkpost/php-sparkpost/compare/2.0.0...2.0.1
[2.0.0]: https://github.com/sparkpost/php-sparkpost/compare/1.2.1...2.0.0
[1.2.1]: https://github.com/sparkpost/php-sparkpost/compare/1.2.0...1.2.1
[1.2.0]: https://github.com/sparkpost/php-sparkpost/compare/v1.1.0...1.2.0
[1.1.0]: https://github.com/sparkpost/php-sparkpost/compare/v1.0.3...v1.1.0
[1.0.3]: https://github.com/sparkpost/php-sparkpost/compare/v1.0.2...v1.0.3
[1.0.2]: https://github.com/sparkpost/php-sparkpost/compare/v1.0.1...v1.0.2
[1.0.1]: https://github.com/sparkpost/php-sparkpost/compare/v1.0.0...v1.0.1
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to php-sparkpost
Transparency is one of our core values, and we encourage developers to contribute and become part of the SparkPost developer community.
The following is a set of guidelines for contributing to php-sparkpost,
which is hosted in the [SparkPost Organization](https://github.com/sparkpost) on GitHub.
These are just guidelines, not rules, use your best judgment and feel free to
propose changes to this document in a pull request.
## Submitting Issues
* You can create an issue [here](https://github.com/sparkpost/php-sparkpost/issues/new), but
before doing that please read the notes below on debugging and submitting issues,
and include as many details as possible with your report.
* Include the version of php-sparkpost you are using.
* Perform a [cursory search](https://github.com/SparkPost/php-sparkpost/issues?q=is%3Aissue+is%3Aopen)
to see if a similar issue has already been submitted.
## Development
### Setup (Getting the Tools)
#### Install Composer
```
curl -sS https://getcomposer.org/installer | php
```
Add composer install directory to $PATH `~/.composer/vendor/bin/`
### phpenv
[phpenv](https://github.com/phpenv/phpenv-installer) is useful for testing locally across different PHP versions.
### Developing your app against a local version of the SparkPost library
If 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:
home
- php-sparkpost
- my-app
- composer.json
- .. etc
Use the following for `my-app/composer.json`:
```json
{
"name": "sparkpost/php_simple_email_send",
"description": "a small test program to send an email",
"repositories": [
{
"type": "path",
"url": "../php-sparkpost"
}
],
"require": {
"php-http/guzzle6-adapter": "^1.1",
"guzzlehttp/guzzle": "^6.0",
"sparkpost/sparkpost": "dev-master"
}
}
```
### Memory
We 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`.
#### Install XDebug for code coverage generation
Follow the instructions at [xdebug.org](http://xdebug.org/wizard.php)
#### Development Tool Resources
* https://getcomposer.org/doc/00-intro.md#globally-on-osx-via-homebrew-
* https://phpunit.de/manual/current/en/installation.html
### Local Development
* Fork [this repository](http://github.com/SparkPost/php-sparkpost)
* Clone your fork
* Run `composer install`
* Write code!
### Contribution Steps
#### Guidelines
- Provide documentation for any newly added code.
- Provide tests for any newly added code.
- Follow [PSR-2](http://www.php-fig.org/psr/psr-2/) (_will be auto-enforced by php-cs-fixer in a later step_)
1. 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)
1. Write corresponding tests and code (only what is needed to satisfy the issue and tests please)
* Include your tests in the 'test' directory in an appropriate test file
* Write code to satisfy the tests
1. Ensure automated tests pass
1. Run `composer run-script fix-style` to enforce PSR-2 style
1. 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).
### Testing
Once you are setup for local development:
* You can execute the unit tests using: `composer test`
* You can view coverage information by viewing: `open test/output/report/index.html`
## Releasing
* 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.
* Once it's been merged down, create a release tag in git.
* Composer will automatically pickup the new tag and present it as a release.
================================================
FILE: LICENSE.txt
================================================
Copyright 2014 Message Systems, Inc. or its affiliates.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: MIGRATION.md
================================================
# Migration Guide
This is a guide to help you make the switch when the SparkPost PHP library changes major versions.
## Migrating from 1.0 to 2.0
## Package name change
The composer package name has changed from `sparkpost/php-sparkpost` to `sparkpost/sparkpost`
### No more setupUnwrapped
We 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).
### `transmission` becomes `transmissions`
Transmission endpoints are now under `$sparky->transmissions` instead of `$sparky->transmission` to map more directly to the [API docs](https://developers.sparkpost.com/api/).
* We no longer map parameters to the API - we simplified. Instead custom mapping, now set the payload to match the API docs.
* 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)
### Switched from Ivory Http Adapter to HTTPlug
Ivory Http Adapter was deprecated in favor of HTTPlug.
### Asynchronous support
We addeded in support for [asynchronous calls](https://github.com/SparkPost/php-sparkpost/tree/2.0.0#asynchronous) (assuming your client supports it).
### Example
#### 2.0
```php
try {
$sparky->setOptions([ 'async' => false ]);
// Build your email and send it!
$results = $sparky->transmissions->post([
'content'=>[
'from'=>[
'name' => 'From Envelope',
'email' => 'from@sparkpostbox.com>'
],
'subject'=>'First Mailing From PHP',
'html'=>'<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent your very first mailing!</p></body></html>',
'text'=>'Congratulations, {{name}}!! You just sent your very first mailing!',
],
'substitution_data'=>['name'=>'YOUR FIRST NAME'],
'recipients'=>[
[
'address'=>[
'name'=>'YOUR FULL NAME',
'email'=>'YOUR EMAIL ADDRESS'
]
]
]
]);
echo 'Woohoo! You just sent your first mailing!';
} catch (\Exception $err) {
echo 'Whoops! Something went wrong';
var_dump($err);
}
```
#### 1.0
```php
try {
// Build your email and send it!
$results = $sparky->transmission->send([
'from'=>[
'name' => 'From Envelope',
'email' => 'from@sparkpostbox.com>'
],
'html'=>'<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent your very first mailing!</p></body></html>',
'text'=>'Congratulations, {{name}}!! You just sent your very first mailing!',
'substitutionData'=>['name'=>'YOUR FIRST NAME'],
'subject'=>'First Mailing From PHP',
'recipients'=>[
[
'address'=>[
'name'=>'YOUR FULL NAME',
'email'=>'YOUR EMAIL ADDRESS'
]
]
]
]);
echo 'Woohoo! You just sent your first mailing!';
} catch (\Exception $err) {
echo 'Whoops! Something went wrong';
var_dump($err);
}
```
================================================
FILE: README.md
================================================
<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>
[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.
# SparkPost PHP Library
[](https://travis-ci.org/SparkPost/php-sparkpost)
[](https://coveralls.io/github/SparkPost/php-sparkpost?branch=master)
[](https://packagist.org/packages/sparkpost/sparkpost)
[](https://packagist.org/packages/sparkpost/sparkpost)
The official PHP library for using [the SparkPost REST API](https://developers.sparkpost.com/api/).
Before 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.
## Installation
**Please note: The composer package `sparkpost/php-sparkpost` has been changed to `sparkpost/sparkpost` starting with version 2.0.**
The recommended way to install the SparkPost PHP Library is through composer.
```
# Install Composer
curl -sS https://getcomposer.org/installer | php
```
Sparkpost 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.
```
composer require php-http/guzzle6-adapter "^1.1"
composer require guzzlehttp/guzzle "^6.0"
```
Next, run the Composer command to install the SparkPost PHP Library:
```
composer require sparkpost/sparkpost
```
After installing, you need to require Composer's autoloader:
```php
require 'vendor/autoload.php';
use SparkPost\SparkPost;
```
**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.
## Running with IDEs
When 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`:
```
Exception has occurred.
Http\Discovery\Exception\PuliUnavailableException: Puli Factory is not available
```
[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.
You can prevent the exception, by setting the discovery strategies, prior to creating the adapter object:
```php
// Prevent annoying "Puli exception" during work with xdebug / IDE
// See https://github.com/getsentry/sentry-php/issues/801
\Http\Discovery\ClassDiscovery::setStrategies([
// \Http\Discovery\Strategy\PuliBetaStrategy::class, // Deliberately disabled
\Http\Discovery\Strategy\CommonClassesStrategy::class,
\Http\Discovery\Strategy\CommonPsr17ClassesStrategy::class,
]);
```
## Setting up a Request Adapter
Because of dependency collision, we have opted to use a request adapter rather than
requiring a request library. This means that your application will need to pass in
a 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
need to require one and create a client from it and pass it along. The example below uses the GuzzleHttp Client Library.
A Client can be setup like so:
```php
<?php
require 'vendor/autoload.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
$sparky = new SparkPost($httpClient, ['key'=>'YOUR_API_KEY']);
?>
```
## Initialization
#### new Sparkpost(httpClient, options)
* `httpClient`
* Required: Yes
* HTTP client or adapter supported by HTTPlug
* `options`
* Required: Yes
* Type: `String` or `Array`
* A valid Sparkpost API key or an array of options
* `options.key`
* Required: Yes
* Type: `String`
* A valid Sparkpost API key
* `options.host`
* Required: No
* Type: `String`
* Default: `api.sparkpost.com`
* `options.protocol`
* Required: No
* Type: `String`
* Default: `https`
* `options.port`
* Required: No
* Type: `Number`
* Default: 443
* `options.version`
* Required: No
* Type: `String`
* Default: `v1`
* `options.async`
* Required: No
* Type: `Boolean`
* Default: `true`
* `async` defines if the `request` function sends an asynchronous or synchronous request. If your client does not support async requests set this to `false`
* `options.retries`
* Required: No
* Type: `Number`
* Default: `0`
* `retries` controls how many API call attempts the client makes after receiving a 5xx response
* `options.debug`
* Required: No
* Type: `Boolean`
* Default: `false`
* If `debug` is true, then all `SparkPostResponse` and `SparkPostException` instances will return any array of the request values through the function `getRequest`
## Methods
### request(method, uri [, payload [, headers]])
* `method`
* Required: Yes
* Type: `String`
* HTTP method for request
* `uri`
* Required: Yes
* Type: `String`
* The URI to receive the request
* `payload`
* Required: No
* Type: `Array`
* 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.
* `headers`
* Required: No
* Type: `Array`
* Custom headers to be sent with the request.
### syncRequest(method, uri [, payload [, headers]])
Sends a synchronous request to the SparkPost API and returns a `SparkPostResponse`
### asyncRequest(method, uri [, payload [, headers]])
Sends an asynchronous request to the SparkPost API and returns a `SparkPostPromise`
### setHttpClient(httpClient)
* `httpClient`
* Required: Yes
* HTTP client or adapter supported by HTTPlug
### setOptions(options)
* `options`
* Required: Yes
* Type: `Array`
* See constructor
## Endpoints
### transmissions
* **post(payload)**
* `payload` - see request options
* `payload.cc`
* Required: No
* Type: `Array`
* Recipients to receive a carbon copy of the transmission
* `payload.bcc`
* Required: No
* Type: `Array`
* Recipients to discreetly receive a carbon copy of the transmission
## Examples
### Send An Email Using The Transmissions Endpoint
```php
<?php
require 'vendor/autoload.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// Good practice to not have API key literals in code - set an environment variable instead
// For simple example, use synchronous model
$sparky = new SparkPost($httpClient, ['key' => getenv('SPARKPOST_API_KEY'), 'async' => false]);
try {
$response = $sparky->transmissions->post([
'content' => [
'from' => [
'name' => 'SparkPost Team',
'email' => 'from@sparkpostbox.com',
],
'subject' => 'First Mailing From PHP',
'html' => '<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent your very first mailing!</p></body></html>',
'text' => 'Congratulations, {{name}}!! You just sent your very first mailing!',
],
'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],
'recipients' => [
[
'address' => [
'name' => 'YOUR_NAME',
'email' => 'YOUR_EMAIL',
],
],
],
'cc' => [
[
'address' => [
'name' => 'ANOTHER_NAME',
'email' => 'ANOTHER_EMAIL',
],
],
],
'bcc' => [
[
'address' => [
'name' => 'AND_ANOTHER_NAME',
'email' => 'AND_ANOTHER_EMAIL',
],
],
],
]);
} catch (\Exception $error) {
var_dump($error);
}
print($response->getStatusCode());
$results = $response->getBody()['results'];
var_dump($results);
?>
```
More examples [here](./examples/):
### [Transmissions](./examples/transmissions/)
- Create with attachment
- Create with recipient list
- Create with cc and bcc
- Create with template
- Create
- Delete (scheduled transmission by campaign_id *only*)
### [Templates](./examples/templates/)
- Create
- Get
- Get (list) all
- Update
- Delete
### [Message Events](./examples/message-events/)
- get
- get (with retry logic)
### Send An API Call Using The Base Request Function
We provide a base request function to access any of our API resources.
```php
<?php
require 'vendor/autoload.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
$sparky = new SparkPost($httpClient, [
'key' => getenv('SPARKPOST_API_KEY'),
'async' => false]);
$webhookId = 'afd20f50-865a-11eb-ac38-6d7965d56459';
$response = $sparky->request('DELETE', 'webhooks/' . $webhookId);
print($response->getStatusCode());
?>
```
> Be sure to not have a leading `/` in your resource URI.
For complete list of resources, refer to [API documentation](https://developers.sparkpost.com/api/).
## Handling Responses
The API calls either return a `SparkPostPromise` or `SparkPostResponse` depending on if `async` is `true` or `false`
### Synchronous
```php
$sparky->setOptions(['async' => false]);
try {
$response = ... // YOUR API CALL GOES HERE
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
}
catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
```
### Asynchronous
Asynchronous an be handled in two ways: by passing callbacks or waiting for the promise to be fulfilled. Waiting acts like synchronous request.
##### Wait (Synchronous)
```php
$promise = ... // YOUR API CALL GOES HERE
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
echo "I will print out after the promise is fulfilled";
```
##### Then (Asynchronous)
```php
$promise = ... // YOUR API CALL GOES HERE
$promise->then(
// Success callback
function ($response) {
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
},
// Failure callback
function (Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
);
echo "I will print out before the promise is fulfilled";
// You can combine multiple promises using \GuzzleHttp\Promise\all() and other functions from the library.
$promise->wait();
```
## Handling Exceptions
An 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.
### SparkPostException
* **getCode()**
* Returns the response status code of `400` or higher
* **getMessage()**
* Returns the exception message
* **getBody()**
* If there is a response body it returns it as an `Array`. Otherwise it returns `null`.
* **getRequest()**
* Returns an array with the request values `method`, `url`, `headers`, `body` when `debug` is `true`
### Contributing
See [contributing](https://github.com/SparkPost/php-sparkpost/blob/master/CONTRIBUTING.md).
================================================
FILE: composer.json
================================================
{
"name": "sparkpost/sparkpost",
"description": "Client library for interfacing with the SparkPost API.",
"license": "MIT",
"authors": [
{
"name": "SparkPost"
}
],
"minimum-stability": "stable",
"scripts": {
"test": "XDEBUG_MODE=coverage ./vendor/bin/phpunit",
"fix-style": "php-cs-fixer fix ."
},
"require": {
"php": "^7.1 || ^8.0",
"php-http/httplug": "^1.0 || ^2.0",
"php-http/message": "^1.0",
"php-http/client-implementation": "^1.0",
"php-http/discovery": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^8.0 || ^9.0",
"php-http/guzzle6-adapter": "^1.0",
"mockery/mockery": "^1.3",
"nyholm/nsa": "^1.0",
"php-coveralls/php-coveralls": "^2.4",
"friendsofphp/php-cs-fixer": "^2.18"
},
"autoload": {
"psr-4": {
"SparkPost\\": "lib/SparkPost"
}
},
"autoload-dev": {
"psr-4": {
"SparkPost\\Test\\": "test/unit"
}
}
}
================================================
FILE: examples/bootstrap.php
================================================
<?php
require_once dirname(__FILE__).'/../vendor/autoload.php';
================================================
FILE: examples/debug/index.php
================================================
<?php
namespace Examples\Templates;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
/*
* configure options in example-options.json
*/
$sparky = new SparkPost($httpClient, [
"key" => getenv('SPARKPOST_API_KEY'),
// fetch API KEY from environment variable
"debug" => true
]);
$promise = $sparky->request('GET', 'templates');
try {
$response = $promise->wait();
var_dump($response);
echo "Request:\n";
print_r($response->getRequest());
echo "Response:\n";
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo "Request:\n";
print_r($e->getRequest());
echo "Exception:\n";
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/message-events/get_message_events.php
================================================
<?php
namespace Examples\Templates;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
// New endpoint - https://developers.sparkpost.com/api/events/
$promise = $sparky->request('GET', 'events/message', [
'campaign_ids' => 'CAMPAIGN_ID',
]);
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/message-events/get_message_events_with_retry_logic.php
================================================
<?php
namespace Examples\Templates;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY'), "retries" => 3]);
// New endpoint - https://developers.sparkpost.com/api/events/
$promise = $sparky->request('GET', 'events/message', [
'campaign_ids' => 'CAMPAIGN_ID',
]);
/**
* If this fails with a 5xx it will have failed 4 times
*/
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
if ($e->getCode() >= 500 && $e->getCode() <= 599) {
echo "Wow, this failed epically";
}
}
================================================
FILE: examples/templates/create_template.php
================================================
<?php
namespace Examples\Templates;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
$template_name = "PHP example template";
$template_id = "PHP-example-template";
// put your own sending domain here
$sending_domain = "steve2-test.trymsys.net";
// Valid short template content examples
$plain_text = 'Write your text message part here.';
$html = <<<HTML
<!DOCTYPE html>
<html lang="en">
<body>
<p><strong>Write your HTML message part here</strong></p>
</body>
</html>
HTML;
$amp_html = <<<HTML
<!doctype html>
<html ⚡4email>
<head>
<meta charset="utf-8">
<style amp4email-boilerplate>body{visibility:hidden}</style>
<script async src="https://cdn.ampproject.org/v0.js"></script>
</head>
<body>
Hello World! Let's get started using AMP HTML together!
</body>
</html>
HTML;
$promise = $sparky->request('POST', 'templates', [
'name' => $template_name,
'id' => $template_id,
'content' => [
'from' => "from@$sending_domain",
'subject' => 'Your Subject',
'text' => $plain_text,
'html' => $html,
'amp_html' => $amp_html,
],
]);
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/templates/delete_template.php
================================================
<?php
namespace Examples\Templates;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
$template_id = "PHP-example-template";
$promise = $sparky->request('DELETE', "templates/$template_id");
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/templates/get_all_templates.php
================================================
<?php
namespace Examples\Templates;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
$promise = $sparky->request('GET', 'templates');
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/templates/get_template.php
================================================
<?php
namespace Examples\Templates;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
$template_id = "PHP-example-template";
$promise = $sparky->request('GET', "templates/$template_id?draft=true");
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/templates/preview_template.php
================================================
<?php
namespace Examples\Templates;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
$template_id = "PHP-example-template";
$promise = $sparky->request('POST', "templates/$template_id/preview?draft=true", [
'substitution_data' => [
'some_key' => 'some_value',
],
]);
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/templates/update_template.php
================================================
<?php
namespace Examples\Templates;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
$template_id = "PHP-example-template";
$promise = $sparky->request('PUT', "templates/$template_id", [
'options' => [
'open_tracking' => true,
],
]);
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/transmissions/create_transmission.php
================================================
<?php
namespace Examples\Transmissions;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
// put your own sending domain and test recipient address here
$sending_domain = "steve2-test.trymsys.net";
$your_email = "bob@sink.sparkpostmail.com";
$promise = $sparky->transmissions->post([
'content' => [
'from' => [
'name' => 'SparkPost Team',
'email' => "from@$sending_domain",
],
'subject' => 'First Mailing From PHP',
'html' => '<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent your very first mailing!</p></body></html>',
'text' => 'Congratulations, {{name}}! You just sent your very first mailing!',
],
'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],
'recipients' => [
[
'address' => [
'name' => 'YOUR_NAME',
'email' => $your_email,
],
],
],
]);
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/transmissions/create_transmission_with_attachment.php
================================================
<?php
namespace Examples\Transmissions;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
$filePath = dirname(__FILE__).'/';
$fileName = 'sparkpost.png';
$fileType = mime_content_type($filePath.$fileName);
$fileData = base64_encode(file_get_contents($filePath.$fileName));
// put your own sending domain and test recipient address here
$sending_domain = "steve2-test.trymsys.net";
$your_email = "bob@sink.sparkpostmail.com";
$promise = $sparky->transmissions->post([
'content' => [
'from' => [
'name' => 'SparkPost Team',
'email' => "from@$sending_domain",
],
'subject' => 'Mailing With Attachment From PHP',
'html' => '<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent an email with an attachment!</p></body></html>',
'text' => 'Congratulations, {{name}}! You just sent an email with an attachment',
'attachments' => [
[
'name' => $fileName,
'type' => $fileType,
'data' => $fileData,
],
],
],
'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],
'recipients' => [
[
'address' => [
'name' => 'YOUR_NAME',
'email' => $your_email,
],
],
],
]);
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/transmissions/create_transmission_with_cc_and_bcc.php
================================================
<?php
namespace Examples\Transmissions;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
// put your own sending domain and test recipient address here
$sending_domain = "steve2-test.trymsys.net";
$your_email = "bob@sink.sparkpostmail.com";
$your_cc = "alice@sink.sparkpostmail.com";
$your_bcc = "charles@sink.sparkpostmail.com";
$promise = $sparky->transmissions->post([
'content' => [
'from' => [
'name' => 'SparkPost Team',
'email' => "from@$sending_domain",
],
'subject' => 'Mailing With CC and BCC From PHP',
'html' => '<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent your very first mailing with CC and BCC recipients!</p></body></html>',
'text' => 'Congratulations, {{name}}! You just sent your very first mailing with CC and BCC recipients!',
],
'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],
'recipients' => [
[
'address' => [
'name' => 'YOUR_NAME',
'email' => $your_email,
],
],
],
'cc' => [
[
'address' => [
'name' => 'ANOTHER_NAME',
'email' => $your_cc,
],
],
],
'bcc' => [
[
'address' => [
'name' => 'AND_ANOTHER_NAME',
'email' => $your_bcc,
],
],
],
]);
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/transmissions/create_transmission_with_recipient_list.php
================================================
<?php
namespace Examples\Transmissions;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
// put your own sending domain and test recipient address here
$sending_domain = "steve2-test.trymsys.net";
// The ID of a list in your SparkPost account
$my_list = "mylist1";
$promise = $sparky->transmissions->post([
'content' => [
'from' => [
'name' => 'SparkPost Team',
'email' => "from@$sending_domain",
],
'subject' => 'Mailing With Recipient List From PHP',
'html' => '<html><body><h1>Congratulations, {{name}}!</h1><p>You just sent an email to everyone on your recipient list!</p></body></html>',
'text' => 'Congratulations, {{name}}! You just sent an email to everyone on your recipient list!',
],
'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],
'recipients' => ['list_id' => $my_list],
]);
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/transmissions/create_transmission_with_template.php
================================================
<?php
namespace Examples\Transmissions;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
// put your own sending domain and test recipient address here
$sending_domain = "steve2-test.trymsys.net";
$your_email = "bob@sink.sparkpostmail.com";
$template_id = "PHP-example-template";
$promise = $sparky->transmissions->post([
'content' => ['template_id' => $template_id],
'substitution_data' => ['name' => 'YOUR_FIRST_NAME'],
'recipients' => [
[
'address' => [
'name' => 'YOUR_NAME',
'email' => $your_email,
],
],
],
]);
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/transmissions/delete_transmission.php
================================================
<?php
namespace Examples\Transmissions;
require dirname(__FILE__).'/../bootstrap.php';
use SparkPost\SparkPost;
use GuzzleHttp\Client;
use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
$httpClient = new GuzzleAdapter(new Client());
// In these examples, fetch API key from environment variable
$sparky = new SparkPost($httpClient, ["key" => getenv('SPARKPOST_API_KEY')]);
// Delete *scheduled* transmissions (only) by *campaign ID* (only)
// See https://developers.sparkpost.com/api/transmissions/#transmissions-delete-delete-a-scheduled-transmission
$promise = $sparky->transmissions->delete('?campaign_id=white_christmas');
try {
$response = $promise->wait();
echo $response->getStatusCode()."\n";
print_r($response->getBody())."\n";
} catch (\Exception $e) {
echo $e->getCode()."\n";
echo $e->getMessage()."\n";
}
================================================
FILE: examples/transmissions/get_all_transmissions.php
================================================
<?php
// Feature has been deprecated
// See https://developers.sparkpost.com/api/transmissions/#transmissions-get-retrieve-a-scheduled-transmission
================================================
FILE: examples/transmissions/get_transmission.php
================================================
<?php
// Feature has been deprecated
// See https://developers.sparkpost.com/api/transmissions/#transmissions-get-retrieve-a-scheduled-transmission
================================================
FILE: lib/SparkPost/Resource.php
================================================
<?php
namespace SparkPost;
/**
* Class Resource.
*
* @deprecated Soft reservations placed on name Resource (as of PHP7)
*/
class Resource extends ResourceBase
{
}
================================================
FILE: lib/SparkPost/ResourceBase.php
================================================
<?php
namespace SparkPost;
/**
* Class ResourceBase.
*/
class ResourceBase
{
/**
* SparkPost object used to make requests.
*/
protected $sparkpost;
/**
* The api endpoint that gets prepended to all requests send through this resource.
*/
protected $endpoint;
/**
* Sets up the Resource.
*
* @param SparkPost $sparkpost - the sparkpost instance that this resource is attached to
* @param string $endpoint - the endpoint that this resource wraps
*/
public function __construct(SparkPost $sparkpost, $endpoint)
{
$this->sparkpost = $sparkpost;
$this->endpoint = $endpoint;
}
/**
* Sends get request to API at the set endpoint.
*
* @see SparkPost->request()
*/
public function get($uri = '', $payload = [], $headers = [])
{
return $this->request('GET', $uri, $payload, $headers);
}
/**
* Sends put request to API at the set endpoint.
*
* @see SparkPost->request()
*/
public function put($uri = '', $payload = [], $headers = [])
{
return $this->request('PUT', $uri, $payload, $headers);
}
/**
* Sends post request to API at the set endpoint.
*
* @see SparkPost->request()
*/
public function post($payload = [], $headers = [])
{
return $this->request('POST', '', $payload, $headers);
}
/**
* Sends delete request to API at the set endpoint.
*
* @see SparkPost->request()
*/
public function delete($uri = '', $payload = [], $headers = [])
{
return $this->request('DELETE', $uri, $payload, $headers);
}
/**
* Sends requests to SparkPost object to the resource endpoint.
*
* @see SparkPost->request()
*
* @return SparkPostPromise or SparkPostResponse depending on sync or async request
*/
public function request($method = 'GET', $uri = '', $payload = [], $headers = [])
{
if (is_array($uri)) {
$headers = $payload;
$payload = $uri;
$uri = '';
}
$uri = $this->endpoint.'/'.$uri;
return $this->sparkpost->request($method, $uri, $payload, $headers);
}
}
================================================
FILE: lib/SparkPost/SparkPost.php
================================================
<?php
namespace SparkPost;
use Http\Client\HttpClient;
use Http\Client\HttpAsyncClient;
use Http\Discovery\MessageFactoryDiscovery;
use Http\Message\RequestFactory;
use Psr\Http\Message\RequestInterface;
class SparkPost
{
/**
* @var string Library version, used for setting User-Agent
*/
private $version = '2.3.0';
/**
* @var HttpClient|HttpAsyncClient used to make requests
*/
private $httpClient;
/**
* @var RequestFactory
*/
private $messageFactory;
/**
* @var array Options for requests
*/
private $options;
/**
* Default options for requests that can be overridden with the setOptions function.
*/
private static $defaultOptions = [
'host' => 'api.sparkpost.com',
'protocol' => 'https',
'port' => 443,
'key' => '',
'version' => 'v1',
'async' => true,
'debug' => false,
'retries' => 0
];
/**
* @var Transmission Instance of Transmission class
*/
public $transmissions;
/**
* Sets up the SparkPost instance.
*
* @param HttpClient $httpClient - An httplug client or adapter
* @param array $options - An array to overide default options or a string to be used as an API key
*/
public function __construct($httpClient, array $options)
{
$this->setOptions($options);
$this->setHttpClient($httpClient);
$this->setupEndpoints();
}
/**
* Sends either sync or async request based on async option.
*
* @param string $method
* @param string $uri
* @param array $payload - either used as the request body or url query params
* @param array $headers
*
* @return SparkPostPromise|SparkPostResponse Promise or Response depending on sync or async request
*/
public function request($method = 'GET', $uri = '', $payload = [], $headers = [])
{
if ($this->options['async'] === true) {
return $this->asyncRequest($method, $uri, $payload, $headers);
} else {
return $this->syncRequest($method, $uri, $payload, $headers);
}
}
/**
* Sends sync request to SparkPost API.
*
* @param string $method
* @param string $uri
* @param array $payload
* @param array $headers
*
* @return SparkPostResponse
*
* @throws SparkPostException
*/
public function syncRequest($method = 'GET', $uri = '', $payload = [], $headers = [])
{
$requestValues = $this->buildRequestValues($method, $uri, $payload, $headers);
$request = call_user_func_array(array($this, 'buildRequestInstance'), $requestValues);
$retries = $this->options['retries'];
try {
if ($retries > 0) {
$resp = $this->syncReqWithRetry($request, $retries);
} else {
$resp = $this->httpClient->sendRequest($request);
}
return new SparkPostResponse($resp, $this->ifDebug($requestValues));
} catch (\Exception $exception) {
throw new SparkPostException($exception, $this->ifDebug($requestValues));
}
}
private function syncReqWithRetry($request, $retries)
{
$resp = $this->httpClient->sendRequest($request);
$status = $resp->getStatusCode();
if ($status >= 500 && $status <= 599 && $retries > 0) {
return $this->syncReqWithRetry($request, $retries-1);
}
return $resp;
}
/**
* Sends async request to SparkPost API.
*
* @param string $method
* @param string $uri
* @param array $payload
* @param array $headers
*
* @return SparkPostPromise
*/
public function asyncRequest($method = 'GET', $uri = '', $payload = [], $headers = [])
{
if ($this->httpClient instanceof HttpAsyncClient) {
$requestValues = $this->buildRequestValues($method, $uri, $payload, $headers);
$request = call_user_func_array(array($this, 'buildRequestInstance'), $requestValues);
$retries = $this->options['retries'];
if ($retries > 0) {
return new SparkPostPromise($this->asyncReqWithRetry($request, $retries), $this->ifDebug($requestValues));
} else {
return new SparkPostPromise($this->httpClient->sendAsyncRequest($request), $this->ifDebug($requestValues));
}
} else {
throw new \Exception('Your http client does not support asynchronous requests. Please use a different client or use synchronous requests.');
}
}
private function asyncReqWithRetry($request, $retries)
{
return $this->httpClient->sendAsyncRequest($request)->then(function($response) use ($request, $retries) {
$status = $response->getStatusCode();
if ($status >= 500 && $status <= 599 && $retries > 0) {
return $this->asyncReqWithRetry($request, $retries-1);
}
return $response;
});
}
/**
* Builds request values from given params.
*
* @param string $method
* @param string $uri
* @param array $payload
* @param array $headers
*
* @return array $requestValues
*/
public function buildRequestValues($method, $uri, $payload, $headers)
{
$method = trim(strtoupper($method));
if ($method === 'GET') {
$params = $payload;
$body = [];
} else {
$params = [];
$body = $payload;
}
$url = $this->getUrl($uri, $params);
$headers = $this->getHttpHeaders($headers);
// old form-feed workaround now removed
$body = json_encode($body);
return [
'method' => $method,
'url' => $url,
'headers' => $headers,
'body' => $body,
];
}
/**
* Build RequestInterface from given params.
*
* @param array $requestValues
*
* @return RequestInterface
*/
public function buildRequestInstance($method, $url, $headers, $body)
{
return $this->getMessageFactory()->createRequest($method, $url, $headers, $body);
}
/**
* Build RequestInterface from given params.
*
* @param array $requestValues
*
* @return RequestInterface
*/
public function buildRequest($method, $uri, $payload, $headers)
{
$requestValues = $this->buildRequestValues($method, $uri, $payload, $headers);
return call_user_func_array(array($this, 'buildRequestInstance'), $requestValues);
}
/**
* Returns an array for the request headers.
*
* @param array $headers - any custom headers for the request
*
* @return array $headers - headers for the request
*/
public function getHttpHeaders($headers = [])
{
$constantHeaders = [
'Authorization' => $this->options['key'],
'Content-Type' => 'application/json',
'User-Agent' => 'php-sparkpost/'.$this->version,
];
foreach ($constantHeaders as $key => $value) {
$headers[$key] = $value;
}
return $headers;
}
/**
* Builds the request url from the options and given params.
*
* @param string $path - the path in the url to hit
* @param array $params - query parameters to be encoded into the url
*
* @return string $url - the url to send the desired request to
*/
public function getUrl($path, $params = [])
{
$options = $this->options;
$paramsArray = [];
foreach ($params as $key => $value) {
if (is_array($value)) {
$value = implode(',', $value);
}
array_push($paramsArray, $key.'='.$value);
}
$paramsString = implode('&', $paramsArray);
return $options['protocol'].'://'.$options['host'].($options['port'] ? ':'.$options['port'] : '').'/api/'.$options['version'].'/'.$path.($paramsString ? '?'.$paramsString : '');
}
/**
* Sets $httpClient to be used for request.
*
* @param HttpClient|HttpAsyncClient $httpClient - the client to be used for request
*
* @return SparkPost
*/
public function setHttpClient($httpClient)
{
if (!($httpClient instanceof HttpAsyncClient || $httpClient instanceof HttpClient)) {
throw new \LogicException(sprintf('Parameter to SparkPost::setHttpClient must be instance of "%s" or "%s"', HttpClient::class, HttpAsyncClient::class));
}
$this->httpClient = $httpClient;
return $this;
}
/**
* Sets the options from the param and defaults for the SparkPost object.
*
* @param array $options - either an string API key or an array of options
*
* @return SparkPost
*/
public function setOptions($options)
{
// if the options map is a string we should assume that its an api key
if (is_string($options)) {
$options = ['key' => $options];
}
// Validate API key because its required
if (!isset($this->options['key']) && (!isset($options['key']) || !preg_match('/\S/', $options['key']))) {
throw new \Exception('You must provide an API key');
}
$this->options = isset($this->options) ? $this->options : self::$defaultOptions;
// set options, overriding defaults
foreach ($options as $option => $value) {
if (key_exists($option, $this->options)) {
$this->options[$option] = $value;
}
}
return $this;
}
/**
* Returns the given value if debugging, an empty instance otherwise.
*
* @param any $param
*
* @return any $param
*/
private function ifDebug($param)
{
return $this->options['debug'] ? $param : null;
}
/**
* Sets up any endpoints to custom classes e.g. $this->transmissions.
*/
private function setupEndpoints()
{
$this->transmissions = new Transmission($this);
}
/**
* @return RequestFactory
*/
private function getMessageFactory()
{
if (!$this->messageFactory) {
$this->messageFactory = MessageFactoryDiscovery::find();
}
return $this->messageFactory;
}
/**
* @param RequestFactory $messageFactory
*
* @return SparkPost
*/
public function setMessageFactory(RequestFactory $messageFactory)
{
$this->messageFactory = $messageFactory;
return $this;
}
}
================================================
FILE: lib/SparkPost/SparkPostException.php
================================================
<?php
namespace SparkPost;
use Http\Client\Exception\HttpException as HttpException;
class SparkPostException extends \Exception
{
/**
* Variable to hold json decoded body from http response.
*/
private $body = null;
/**
* Array with the request values sent.
*/
private $request;
/**
* Sets up the custom exception and copies over original exception values.
*
* @param Exception $exception - the exception to be wrapped
*/
public function __construct(\Exception $exception, $request = null)
{
$this->request = $request;
$message = $exception->getMessage();
$code = $exception->getCode();
if ($exception instanceof HttpException) {
$message = $exception->getResponse()->getBody()->__toString();
$this->body = json_decode($message, true);
$code = $exception->getResponse()->getStatusCode();
}
parent::__construct($message, $code, $exception->getPrevious());
}
/**
* Returns the request values sent.
*
* @return array $request
*/
public function getRequest()
{
return $this->request;
}
/**
* Returns the body.
*
* @return array $body - the json decoded body from the http response
*/
public function getBody()
{
return $this->body;
}
}
================================================
FILE: lib/SparkPost/SparkPostPromise.php
================================================
<?php
namespace SparkPost;
use Http\Promise\Promise as HttpPromise;
class SparkPostPromise implements HttpPromise
{
/**
* HttpPromise to be wrapped by SparkPostPromise.
*/
private $promise;
/**
* Array with the request values sent.
*/
private $request;
/**
* set the promise to be wrapped.
*
* @param HttpPromise $promise
*/
public function __construct(HttpPromise $promise, $request = null)
{
$this->promise = $promise;
$this->request = $request;
}
/**
* Hand off the response functions to the original promise and return a custom response or exception.
*
* @param callable $onFulfilled - function to be called if the promise is fulfilled
* @param callable $onRejected - function to be called if the promise is rejected
*/
public function then(callable $onFulfilled = null, callable $onRejected = null)
{
$request = $this->request;
return $this->promise->then(function ($response) use ($onFulfilled, $request) {
if (isset($onFulfilled)) {
$onFulfilled(new SparkPostResponse($response, $request));
}
}, function ($exception) use ($onRejected, $request) {
if (isset($onRejected)) {
$onRejected(new SparkPostException($exception, $request));
}
});
}
/**
* Hand back the state.
*
* @return $state - returns the state of the promise
*/
public function getState()
{
return $this->promise->getState();
}
/**
* Wraps the wait function and returns a custom response or throws a custom exception.
*
* @param bool $unwrap
*
* @return SparkPostResponse
*
* @throws SparkPostException
*/
public function wait($unwrap = true)
{
try {
$response = $this->promise->wait($unwrap);
return $response ? new SparkPostResponse($response, $this->request) : $response;
} catch (\Exception $exception) {
throw new SparkPostException($exception, $this->request);
}
}
}
================================================
FILE: lib/SparkPost/SparkPostResponse.php
================================================
<?php
namespace SparkPost;
use Psr\Http\Message\ResponseInterface as ResponseInterface;
use Psr\Http\Message\StreamInterface as StreamInterface;
class SparkPostResponse implements ResponseInterface
{
/**
* ResponseInterface to be wrapped by SparkPostResponse.
*/
private $response;
/**
* Array with the request values sent.
*/
private $request;
/**
* set the response to be wrapped.
*
* @param ResponseInterface $response
*/
public function __construct(ResponseInterface $response, $request = null)
{
$this->response = $response;
$this->request = $request;
}
/**
* Returns the request values sent.
*
* @return array $request
*/
public function getRequest()
{
return $this->request;
}
/**
* Returns the body.
*
* @return array $body - the json decoded body from the http response
*/
public function getBody()
{
$body = $this->response->getBody();
$body_string = $body->__toString();
$json = json_decode($body_string, true);
return $json;
}
/**
* pass these down to the response given in the constructor.
*/
public function getProtocolVersion()
{
return $this->response->getProtocolVersion();
}
public function withProtocolVersion($version)
{
return $this->response->withProtocolVersion($version);
}
public function getHeaders()
{
return $this->response->getHeaders();
}
public function hasHeader($name)
{
return $this->response->hasHeader($name);
}
public function getHeader($name)
{
return $this->response->getHeader($name);
}
public function getHeaderLine($name)
{
return $this->response->getHeaderLine($name);
}
public function withHeader($name, $value)
{
return $this->response->withHeader($name, $value);
}
public function withAddedHeader($name, $value)
{
return $this->response->withAddedHeader($name, $value);
}
public function withoutHeader($name)
{
return $this->response->withoutHeader($name);
}
public function withBody(StreamInterface $body)
{
return $this->response->withBody($body);
}
public function getStatusCode()
{
return $this->response->getStatusCode();
}
public function withStatus($code, $reasonPhrase = '')
{
return $this->response->withStatus($code, $reasonPhrase);
}
public function getReasonPhrase()
{
return $this->response->getReasonPhrase();
}
}
================================================
FILE: lib/SparkPost/Transmission.php
================================================
<?php
namespace SparkPost;
class Transmission extends ResourceBase
{
public function __construct(SparkPost $sparkpost)
{
parent::__construct($sparkpost, 'transmissions');
}
/**
* Send post request to transmission endpoint after formatting cc, bcc, and expanding the shorthand emails.
*
* @return SparkPostPromise or SparkPostResponse depending on sync or async request
*/
public function post($payload = [], $headers = [])
{
if (isset($payload['recipients']) && !isset($payload['recipients']['list_id'])) {
$payload = $this->formatPayload($payload);
}
return parent::post($payload, $headers);
}
/**
* Runs the given payload through the formatting functions.
*
* @param array $payload - the request body
*
* @return array - the modified request body
*/
public function formatPayload($payload)
{
$payload = $this->formatBlindCarbonCopy($payload); //Fixes BCCs into payload
$payload = $this->formatCarbonCopy($payload); //Fixes CCs into payload
$payload = $this->formatShorthandRecipients($payload); //Fixes shorthand recipients format
return $payload;
}
/**
* Formats bcc list into recipients list.
*
* @param array $payload - the request body
*
* @return array - the modified request body
*/
private function formatBlindCarbonCopy($payload)
{
//If there's a list of BCC recipients, move them into the correct format
if (isset($payload['bcc'])) {
$payload = $this->addListToRecipients($payload, 'bcc');
}
return $payload;
}
/**
* Formats cc list into recipients list and adds the CC header to the content.
*
* @param array $payload - the request body
*
* @return array - the modified request body
*/
private function formatCarbonCopy($payload)
{
if (isset($payload['cc'])) {
$ccAddresses = [];
for ($i = 0; $i < count($payload['cc']); ++$i) {
array_push($ccAddresses, $this->toAddressString($payload['cc'][$i]['address']));
}
// set up the content headers as either what it was before or an empty array
$payload['content']['headers'] = isset($payload['content']['headers']) ? $payload['content']['headers'] : [];
// add cc header
$payload['content']['headers']['CC'] = implode(',', $ccAddresses);
$payload = $this->addListToRecipients($payload, 'cc');
}
return $payload;
}
/**
* Formats all recipients into the long form of [ "name" => "John", "email" => "john@exmmple.com" ].
*
* @param array $payload - the request body
*
* @return array - the modified request body
*/
private function formatShorthandRecipients($payload)
{
if (isset($payload['content']['from'])) {
$payload['content']['from'] = $this->toAddressObject($payload['content']['from']);
}
for ($i = 0; $i < count($payload['recipients']); ++$i) {
$payload['recipients'][$i]['address'] = $this->toAddressObject($payload['recipients'][$i]['address']);
}
return $payload;
}
/**
* Loops through the given listName in the payload and adds all the recipients to the recipients list after removing their names.
*
* @param array $payload - the request body
* @param array $listName - the name of the array in the payload to be moved to the recipients list
*
* @return array - the modified request body
*/
private function addListToRecipients($payload, $listName)
{
$originalAddress = $this->toAddressString($payload['recipients'][0]['address']);
foreach ($payload[$listName] as $recipient) {
$recipient['address'] = $this->toAddressObject($recipient['address']);
$recipient['address']['header_to'] = $originalAddress;
// remove name from address - name is only put in the header for cc and not at all for bcc
if (isset($recipient['address']['name'])) {
unset($recipient['address']['name']);
}
array_push($payload['recipients'], $recipient);
}
//Delete the original object from the payload.
unset($payload[$listName]);
return $payload;
}
/**
* Takes the shorthand form of an email address and converts it to the long form.
*
* @param $address - the shorthand form of an email address "Name <Email address>"
*
* @return array - the longhand form of an email address [ "name" => "John", "email" => "john@exmmple.com" ]
*/
private function toAddressObject($address)
{
$formatted = $address;
if (is_string($formatted)) {
$formatted = [];
if ($this->isEmail($address)) {
$formatted['email'] = $address;
} elseif (preg_match('/"?(.[^"]*)?"?\s*<(.+)>/', $address, $matches)) {
$name = trim($matches[1]);
$formatted['name'] = $matches[1];
$formatted['email'] = $matches[2];
} else {
throw new \Exception('Invalid address format: '.$address);
}
}
return $formatted;
}
/**
* Takes the longhand form of an email address and converts it to the shorthand form.
*
* @param $address - the longhand form of an email address [ "name" => "John", "email" => "john@exmmple.com" ]
* @param string - the shorthand form of an email address "Name <Email address>"
*/
private function toAddressString($address)
{
// convert object to string
if (!is_string($address)) {
if (isset($address['name'])) {
$address = '"'.$address['name'].'" <'.$address['email'].'>';
} else {
$address = $address['email'];
}
}
return $address;
}
/**
* Checks if a string is an email.
*
* @param string $email - a string that might be an email address
* @param bool - true if the given string is an email
*/
private function isEmail($email)
{
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
return true;
} else {
return false;
}
}
}
================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<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">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./lib</directory>
</include>
<report>
<clover outputFile="test/output/clover.xml"/>
<html outputDirectory="test/output/report" lowUpperBound="50" highLowerBound="90"/>
</report>
</coverage>
<testsuites>
<testsuite name="Unit tests">
<directory suffix="Test.php">./test/unit</directory>
</testsuite>
</testsuites>
</phpunit>
================================================
FILE: test/unit/SparkPostResponseTest.php
================================================
<?php
namespace SparkPost\Test;
use PHPUnit\Framework\TestCase;
use SparkPost\SparkPostResponse;
use Mockery;
class SparkPostResponseTest extends TestCase
{
/** @var Mockery\MockInterface|\Psr\Http\Message\ResponseInterface */
private $responseMock;
/** @var string */
private $returnValue;
public function setUp(): void
{
$this->returnValue = 'some_value_to_return';
$this->responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface');
}
public function testGetProtocolVersion()
{
$this->responseMock->shouldReceive('getProtocolVersion')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->getProtocolVersion(), $sparkpostResponse->getProtocolVersion());
}
public function testWithProtocolVersion()
{
$param = 'protocol version';
$this->responseMock->shouldReceive('withProtocolVersion')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->withProtocolVersion($param), $sparkpostResponse->withProtocolVersion($param));
}
public function testGetHeaders()
{
$this->responseMock->shouldReceive('getHeaders')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->getHeaders(), $sparkpostResponse->getHeaders());
}
public function testHasHeader()
{
$param = 'header';
$this->responseMock->shouldReceive('hasHeader')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->hasHeader($param), $sparkpostResponse->hasHeader($param));
}
public function testGetHeader()
{
$param = 'header';
$this->responseMock->shouldReceive('getHeader')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->getHeader($param), $sparkpostResponse->getHeader($param));
}
public function testGetHeaderLine()
{
$param = 'header';
$this->responseMock->shouldReceive('getHeaderLine')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->getHeaderLine($param), $sparkpostResponse->getHeaderLine($param));
}
public function testWithHeader()
{
$param = 'header';
$param2 = 'value';
$this->responseMock->shouldReceive('withHeader')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->withHeader($param, $param2), $sparkpostResponse->withHeader($param, $param2));
}
public function testWithAddedHeader()
{
$param = 'header';
$param2 = 'value';
$this->responseMock->shouldReceive('withAddedHeader')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->withAddedHeader($param, $param2), $sparkpostResponse->withAddedHeader($param, $param2));
}
public function testWithoutHeader()
{
$param = 'header';
$this->responseMock->shouldReceive('withoutHeader')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->withoutHeader($param), $sparkpostResponse->withoutHeader($param));
}
public function testGetRequest()
{
$request = ['some' => 'request'];
$this->responseMock->shouldReceive('getRequest')->andReturn($request);
$sparkpostResponse = new SparkPostResponse($this->responseMock, $request);
$this->assertEquals($sparkpostResponse->getRequest(), $request);
}
public function testWithBody()
{
$param = Mockery::mock('Psr\Http\Message\StreamInterface');
$this->responseMock->shouldReceive('withBody')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->withBody($param), $sparkpostResponse->withBody($param));
}
public function testGetStatusCode()
{
$this->responseMock->shouldReceive('getStatusCode')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->getStatusCode(), $sparkpostResponse->getStatusCode());
}
public function testWithStatus()
{
$param = 'status';
$this->responseMock->shouldReceive('withStatus')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->withStatus($param), $sparkpostResponse->withStatus($param));
}
public function testGetReasonPhrase()
{
$this->responseMock->shouldReceive('getReasonPhrase')->andReturn($this->returnValue);
$sparkpostResponse = new SparkPostResponse($this->responseMock);
$this->assertEquals($this->responseMock->getReasonPhrase(), $sparkpostResponse->getReasonPhrase());
}
}
================================================
FILE: test/unit/SparkPostTest.php
================================================
<?php
namespace SparkPost\Test;
use Http\Client\HttpAsyncClient;
use Http\Client\HttpClient;
use Http\Message\MessageFactory;
use Nyholm\NSA;
use PHPUnit\Framework\TestCase;
use SparkPost\SparkPost;
use SparkPost\SparkPostPromise;
use GuzzleHttp\Promise\FulfilledPromise as GuzzleFulfilledPromise;
use GuzzleHttp\Promise\RejectedPromise as GuzzleRejectedPromise;
use Http\Adapter\Guzzle6\Promise as GuzzleAdapterPromise;
use Mockery;
class SparkPostTest extends TestCase
{
private $clientMock;
/** @var SparkPost */
private $resource;
private $exceptionMock;
private $exceptionBody;
private $responseMock;
private $responseBody;
private $promiseMock;
private $postTransmissionPayload = [
'content' => [
'from' => ['name' => 'Sparkpost Team', 'email' => 'postmaster@sendmailfor.me'],
'subject' => 'First Mailing From PHP',
'text' => 'Congratulations, {{name}}!! You just sent your very first mailing!',
],
'substitution_data' => ['name' => 'Avi'],
'recipients' => [
['address' => 'avi.goldman@sparkpost.com'],
],
];
private $getTransmissionPayload = [
'campaign_id' => 'thanksgiving',
];
public function setUp(): void
{
// response mock up
$responseBodyMock = Mockery::mock();
$this->responseBody = ['results' => 'yay'];
$this->responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface');
$this->responseMock->shouldReceive('getStatusCode')->andReturn(200);
$this->responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);
$responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($this->responseBody));
$errorBodyMock = Mockery::mock();
$this->badResponseBody = ['errors' => []];
$this->badResponseMock = Mockery::mock('Psr\Http\Message\ResponseInterface');
$this->badResponseMock->shouldReceive('getStatusCode')->andReturn(503);
$this->badResponseMock->shouldReceive('getBody')->andReturn($errorBodyMock);
$errorBodyMock->shouldReceive('__toString')->andReturn(json_encode($this->badResponseBody));
// exception mock up
$exceptionResponseMock = Mockery::mock();
$this->exceptionBody = ['results' => 'failed'];
$this->exceptionMock = Mockery::mock('Http\Client\Exception\HttpException');
$this->exceptionMock->shouldReceive('getResponse')->andReturn($exceptionResponseMock);
$exceptionResponseMock->shouldReceive('getStatusCode')->andReturn(500);
$exceptionResponseMock->shouldReceive('getBody->__toString')->andReturn(json_encode($this->exceptionBody));
// promise mock up
$this->promiseMock = Mockery::mock('Http\Promise\Promise');
//setup mock for the adapter
$this->clientMock = Mockery::mock('Http\Adapter\Guzzle6\Client');
$this->clientMock->shouldReceive('sendAsyncRequest')->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andReturn($this->promiseMock);
$this->resource = new SparkPost($this->clientMock, ['key' => 'SPARKPOST_API_KEY']);
}
public function tearDown(): void
{
Mockery::close();
}
public function testRequestSync()
{
$this->resource->setOptions(['async' => false]);
$this->clientMock->shouldReceive('sendRequest')->andReturn($this->responseMock);
$this->assertInstanceOf('SparkPost\SparkPostResponse', $this->resource->request('POST', 'transmissions', $this->postTransmissionPayload));
}
public function testRequestAsync()
{
$promiseMock = Mockery::mock('Http\Promise\Promise');
$this->resource->setOptions(['async' => true]);
$this->clientMock->shouldReceive('sendAsyncRequest')->andReturn($promiseMock);
$this->assertInstanceOf('SparkPost\SparkPostPromise', $this->resource->request('GET', 'transmissions', $this->getTransmissionPayload));
}
public function testDebugOptionWhenFalse() {
$this->resource->setOptions(['async' => false, 'debug' => false]);
$this->clientMock->shouldReceive('sendRequest')->andReturn($this->responseMock);
$response = $this->resource->request('POST', 'transmissions', $this->postTransmissionPayload);
$this->assertEquals($response->getRequest(), null);
}
public function testDebugOptionWhenTrue() {
// setup
$this->resource->setOptions(['async' => false, 'debug' => true]);
// successful
$this->clientMock->shouldReceive('sendRequest')->once()->andReturn($this->responseMock);
$response = $this->resource->request('POST', 'transmissions', $this->postTransmissionPayload);
$this->assertEquals(json_decode($response->getRequest()['body'], true), $this->postTransmissionPayload);
// unsuccessful
$this->clientMock->shouldReceive('sendRequest')->once()->andThrow($this->exceptionMock);
try {
$response = $this->resource->request('POST', 'transmissions', $this->postTransmissionPayload);
}
catch (\Exception $e) {
$this->assertEquals(json_decode($e->getRequest()['body'], true), $this->postTransmissionPayload);
}
}
public function testSuccessfulSyncRequest()
{
$this->clientMock->shouldReceive('sendRequest')->
once()->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andReturn($this->responseMock);
$response = $this->resource->syncRequest('POST', 'transmissions', $this->postTransmissionPayload);
$this->assertEquals($this->responseBody, $response->getBody());
$this->assertEquals(200, $response->getStatusCode());
}
public function testUnsuccessfulSyncRequest()
{
$this->clientMock->shouldReceive('sendRequest')->
once()->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andThrow($this->exceptionMock);
try {
$this->resource->syncRequest('POST', 'transmissions', $this->postTransmissionPayload);
} catch (\Exception $e) {
$this->assertEquals($this->exceptionBody, $e->getBody());
$this->assertEquals(500, $e->getCode());
}
}
public function testSuccessfulSyncRequestWithRetries()
{
$this->clientMock->shouldReceive('sendRequest')->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andReturn($this->badResponseMock, $this->badResponseMock, $this->responseMock);
$this->resource->setOptions(['retries' => 2]);
$response = $this->resource->syncRequest('POST', 'transmissions', $this->postTransmissionPayload);
$this->assertEquals($this->responseBody, $response->getBody());
$this->assertEquals(200, $response->getStatusCode());
}
public function testUnsuccessfulSyncRequestWithRetries()
{
$this->clientMock->shouldReceive('sendRequest')->
once()->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andThrow($this->exceptionMock);
$this->resource->setOptions(['retries' => 2]);
try {
$this->resource->syncRequest('POST', 'transmissions', $this->postTransmissionPayload);
} catch (\Exception $e) {
$this->assertEquals($this->exceptionBody, $e->getBody());
$this->assertEquals(500, $e->getCode());
}
}
public function testSuccessfulAsyncRequestWithWait()
{
$this->promiseMock->shouldReceive('wait')->andReturn($this->responseMock);
$promise = $this->resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);
$response = $promise->wait();
$this->assertEquals($this->responseBody, $response->getBody());
$this->assertEquals(200, $response->getStatusCode());
}
public function testUnsuccessfulAsyncRequestWithWait()
{
$this->promiseMock->shouldReceive('wait')->andThrow($this->exceptionMock);
$promise = $this->resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);
try {
$response = $promise->wait();
} catch (\Exception $e) {
$this->assertEquals($this->exceptionBody, $e->getBody());
$this->assertEquals(500, $e->getCode());
}
}
public function testSuccessfulAsyncRequestWithThen()
{
$guzzlePromise = new GuzzleFulfilledPromise($this->responseMock);
$result = $this->resource->buildRequest('POST', 'transmissions', $this->postTransmissionPayload, []);
$promise = new SparkPostPromise(new GuzzleAdapterPromise($guzzlePromise, $result));
$responseBody = $this->responseBody;
$promise->then(function ($response) use ($responseBody) {
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals($responseBody, $response->getBody());
}, null)->wait();
}
public function testUnsuccessfulAsyncRequestWithThen()
{
$guzzlePromise = new GuzzleRejectedPromise($this->exceptionMock);
$result = $this->resource->buildRequest('POST', 'transmissions', $this->postTransmissionPayload, []);
$promise = new SparkPostPromise(new GuzzleAdapterPromise($guzzlePromise, $result));
$exceptionBody = $this->exceptionBody;
$promise->then(null, function ($exception) use ($exceptionBody) {
$this->assertEquals(500, $exception->getCode());
$this->assertEquals($exceptionBody, $exception->getBody());
})->wait();
}
public function testSuccessfulAsyncRequestWithRetries()
{
$testReq = $this->resource->buildRequest('POST', 'transmissions', $this->postTransmissionPayload, []);
$clientMock = Mockery::mock('Http\Adapter\Guzzle6\Client');
$clientMock->shouldReceive('sendAsyncRequest')->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andReturn(
new GuzzleAdapterPromise(new GuzzleFulfilledPromise($this->badResponseMock), $testReq),
new GuzzleAdapterPromise(new GuzzleFulfilledPromise($this->badResponseMock), $testReq),
new GuzzleAdapterPromise(new GuzzleFulfilledPromise($this->responseMock), $testReq)
);
$resource = new SparkPost($clientMock, ['key' => 'SPARKPOST_API_KEY']);
$resource->setOptions(['async' => true, 'retries' => 2]);
$promise = $resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);
$promise->then(function($resp) {
$this->assertEquals(200, $resp->getStatusCode());
})->wait();
}
public function testUnsuccessfulAsyncRequestWithRetries()
{
$testReq = $this->resource->buildRequest('POST', 'transmissions', $this->postTransmissionPayload, []);
$rejectedPromise = new GuzzleRejectedPromise($this->exceptionMock);
$clientMock = Mockery::mock('Http\Adapter\Guzzle6\Client');
$clientMock->shouldReceive('sendAsyncRequest')->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andReturn(new GuzzleAdapterPromise($rejectedPromise, $testReq));
$resource = new SparkPost($clientMock, ['key' => 'SPARKPOST_API_KEY']);
$resource->setOptions(['async' => true, 'retries' => 2]);
$promise = $resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);
$promise->then(null, function($exception) {
$this->assertEquals(500, $exception->getCode());
$this->assertEquals($this->exceptionBody, $exception->getBody());
})->wait();
}
public function testPromise()
{
$promise = $this->resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);
$this->promiseMock->shouldReceive('getState')->twice()->andReturn('pending');
$this->assertEquals($this->promiseMock->getState(), $promise->getState());
$this->promiseMock->shouldReceive('getState')->twice()->andReturn('rejected');
$this->assertEquals($this->promiseMock->getState(), $promise->getState());
}
public function testUnsupportedAsyncRequest()
{
$this->expectException(\Exception::class);
$this->resource->setHttpClient(Mockery::mock('Http\Client\HttpClient'));
$this->resource->asyncRequest('POST', 'transmissions', $this->postTransmissionPayload);
}
public function testGetHttpHeaders()
{
$headers = $this->resource->getHttpHeaders([
'Custom-Header' => 'testing',
]);
$version = NSA::getProperty($this->resource, 'version');
$this->assertEquals('SPARKPOST_API_KEY', $headers['Authorization']);
$this->assertEquals('application/json', $headers['Content-Type']);
$this->assertEquals('testing', $headers['Custom-Header']);
$this->assertEquals('php-sparkpost/'.$version, $headers['User-Agent']);
}
public function testGetUrl()
{
$url = 'https://api.sparkpost.com:443/api/v1/transmissions?key=value 1,value 2,value 3';
$testUrl = $this->resource->getUrl('transmissions', ['key' => ['value 1', 'value 2', 'value 3']]);
$this->assertEquals($url, $testUrl);
}
public function testSetHttpClient()
{
$mock = Mockery::mock(HttpClient::class);
$this->resource->setHttpClient($mock);
$this->assertEquals($mock, NSA::getProperty($this->resource, 'httpClient'));
}
public function testSetHttpAsyncClient()
{
$mock = Mockery::mock(HttpAsyncClient::class);
$this->resource->setHttpClient($mock);
$this->assertEquals($mock, NSA::getProperty($this->resource, 'httpClient'));
}
public function testSetHttpClientException()
{
$this->expectException(\Exception::class);
$this->resource->setHttpClient(new \stdClass());
}
public function testSetOptionsStringKey()
{
$this->resource->setOptions('SPARKPOST_API_KEY');
$options = NSA::getProperty($this->resource, 'options');
$this->assertEquals('SPARKPOST_API_KEY', $options['key']);
}
public function testSetBadOptions()
{
$this->expectException(\Exception::class);
NSA::setProperty($this->resource, 'options', []);
$this->resource->setOptions(['not' => 'SPARKPOST_API_KEY']);
}
public function testSetMessageFactory()
{
$messageFactory = Mockery::mock(MessageFactory::class);
$this->resource->setMessageFactory($messageFactory);
$this->assertEquals($messageFactory, NSA::invokeMethod($this->resource, 'getMessageFactory'));
}
}
================================================
FILE: test/unit/TransmissionTest.php
================================================
<?php
namespace SparkPost\Test;
use PHPUnit\Framework\TestCase;
use SparkPost\SparkPost;
use Mockery;
class TransmissionTest extends TestCase
{
private $clientMock;
/** @var SparkPost */
private $resource;
private $postTransmissionPayload = [
'content' => [
'from' => ['name' => 'Sparkpost Team', 'email' => 'postmaster@sendmailfor.me'],
'subject' => 'First Mailing From PHP',
'text' => 'Congratulations, {{name}}!! You just sent your very first mailing!',
],
'substitution_data' => ['name' => 'Avi'],
'recipients' => [
[
'address' => [
'name' => 'Vincent',
'email' => 'vincent.song@sparkpost.com',
],
],
['address' => 'test@example.com'],
],
'cc' => [
[
'address' => [
'email' => 'avi.goldman@sparkpost.com',
],
],
],
'bcc' => [
['address' => 'Emely Giraldo <emely.giraldo@sparkpost.com>'],
],
];
private $getTransmissionPayload = [
'campaign_id' => 'thanksgiving',
];
/**
* (non-PHPdoc).
*
* @before
*
* @see PHPUnit_Framework_TestCase::setUp()
*/
public function setUp(): void
{
//setup mock for the adapter
$this->clientMock = Mockery::mock('Http\Adapter\Guzzle6\Client');
$this->resource = new SparkPost($this->clientMock, ['key' => 'SPARKPOST_API_KEY', 'async' => false]);
}
public function tearDown(): void
{
Mockery::close();
}
public function testInvalidEmailFormat()
{
$this->expectException(\Exception::class);
$this->postTransmissionPayload['recipients'][] = [
'address' => 'invalid email format',
];
$response = $this->resource->transmissions->post($this->postTransmissionPayload);
}
public function testGet()
{
$responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface');
$responseBodyMock = Mockery::mock();
$responseBody = ['results' => 'yay'];
$this->clientMock->shouldReceive('sendRequest')->
once()->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andReturn($responseMock);
$responseMock->shouldReceive('getStatusCode')->andReturn(200);
$responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);
$responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($responseBody));
$response = $this->resource->transmissions->get($this->getTransmissionPayload);
$this->assertEquals($responseBody, $response->getBody());
$this->assertEquals(200, $response->getStatusCode());
}
public function testPut()
{
$responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface');
$responseBodyMock = Mockery::mock();
$responseBody = ['results' => 'yay'];
$this->clientMock->shouldReceive('sendRequest')->
once()->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andReturn($responseMock);
$responseMock->shouldReceive('getStatusCode')->andReturn(200);
$responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);
$responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($responseBody));
$response = $this->resource->transmissions->put($this->getTransmissionPayload);
$this->assertEquals($responseBody, $response->getBody());
$this->assertEquals(200, $response->getStatusCode());
}
public function testPost()
{
$responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface');
$responseBodyMock = Mockery::mock();
$responseBody = ['results' => 'yay'];
$this->clientMock->shouldReceive('sendRequest')->
once()->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andReturn($responseMock);
$responseMock->shouldReceive('getStatusCode')->andReturn(200);
$responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);
$responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($responseBody));
$response = $this->resource->transmissions->post($this->postTransmissionPayload);
$this->assertEquals($responseBody, $response->getBody());
$this->assertEquals(200, $response->getStatusCode());
}
public function testPostWithRecipientList()
{
$postTransmissionPayload = $this->postTransmissionPayload;
$postTransmissionPayload['recipients'] = ['list_id' => 'SOME_LIST_ID'];
$responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface');
$responseBodyMock = Mockery::mock();
$responseBody = ['results' => 'yay'];
$this->clientMock->shouldReceive('sendRequest')->
once()->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andReturn($responseMock);
$responseMock->shouldReceive('getStatusCode')->andReturn(200);
$responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);
$responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($responseBody));
$response = $this->resource->transmissions->post();
$this->assertEquals($responseBody, $response->getBody());
$this->assertEquals(200, $response->getStatusCode());
}
public function testDelete()
{
$responseMock = Mockery::mock('Psr\Http\Message\ResponseInterface');
$responseBodyMock = Mockery::mock();
$responseBody = ['results' => 'yay'];
$this->clientMock->shouldReceive('sendRequest')->
once()->
with(Mockery::type('GuzzleHttp\Psr7\Request'))->
andReturn($responseMock);
$responseMock->shouldReceive('getStatusCode')->andReturn(200);
$responseMock->shouldReceive('getBody')->andReturn($responseBodyMock);
$responseBodyMock->shouldReceive('__toString')->andReturn(json_encode($responseBody));
$response = $this->resource->transmissions->delete($this->getTransmissionPayload);
$this->assertEquals($responseBody, $response->getBody());
$this->assertEquals(200, $response->getStatusCode());
}
public function testFormatPayload()
{
$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);
$formattedPayload = $this->resource->transmissions->formatPayload($this->postTransmissionPayload);
$this->assertEquals($correctFormattedPayload, $formattedPayload);
}
}
gitextract_jlhy3dwi/
├── .coveralls.yml
├── .editorconfig
├── .travis.yml
├── AUTHORS.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── MIGRATION.md
├── README.md
├── composer.json
├── examples/
│ ├── bootstrap.php
│ ├── debug/
│ │ └── index.php
│ ├── message-events/
│ │ ├── get_message_events.php
│ │ └── get_message_events_with_retry_logic.php
│ ├── templates/
│ │ ├── create_template.php
│ │ ├── delete_template.php
│ │ ├── get_all_templates.php
│ │ ├── get_template.php
│ │ ├── preview_template.php
│ │ └── update_template.php
│ └── transmissions/
│ ├── create_transmission.php
│ ├── create_transmission_with_attachment.php
│ ├── create_transmission_with_cc_and_bcc.php
│ ├── create_transmission_with_recipient_list.php
│ ├── create_transmission_with_template.php
│ ├── delete_transmission.php
│ ├── get_all_transmissions.php
│ └── get_transmission.php
├── lib/
│ └── SparkPost/
│ ├── Resource.php
│ ├── ResourceBase.php
│ ├── SparkPost.php
│ ├── SparkPostException.php
│ ├── SparkPostPromise.php
│ ├── SparkPostResponse.php
│ └── Transmission.php
├── phpunit.xml.dist
└── test/
└── unit/
├── SparkPostResponseTest.php
├── SparkPostTest.php
└── TransmissionTest.php
SYMBOL INDEX (116 symbols across 10 files)
FILE: lib/SparkPost/Resource.php
class Resource (line 10) | class Resource extends ResourceBase
FILE: lib/SparkPost/ResourceBase.php
class ResourceBase (line 8) | class ResourceBase
method __construct (line 26) | public function __construct(SparkPost $sparkpost, $endpoint)
method get (line 37) | public function get($uri = '', $payload = [], $headers = [])
method put (line 47) | public function put($uri = '', $payload = [], $headers = [])
method post (line 57) | public function post($payload = [], $headers = [])
method delete (line 67) | public function delete($uri = '', $payload = [], $headers = [])
method request (line 79) | public function request($method = 'GET', $uri = '', $payload = [], $he...
FILE: lib/SparkPost/SparkPost.php
class SparkPost (line 11) | class SparkPost
method __construct (line 58) | public function __construct($httpClient, array $options)
method request (line 75) | public function request($method = 'GET', $uri = '', $payload = [], $he...
method syncRequest (line 96) | public function syncRequest($method = 'GET', $uri = '', $payload = [],...
method syncReqWithRetry (line 114) | private function syncReqWithRetry($request, $retries)
method asyncRequest (line 134) | public function asyncRequest($method = 'GET', $uri = '', $payload = []...
method asyncReqWithRetry (line 151) | private function asyncReqWithRetry($request, $retries)
method buildRequestValues (line 172) | public function buildRequestValues($method, $uri, $payload, $headers)
method buildRequestInstance (line 204) | public function buildRequestInstance($method, $url, $headers, $body)
method buildRequest (line 216) | public function buildRequest($method, $uri, $payload, $headers)
method getHttpHeaders (line 229) | public function getHttpHeaders($headers = [])
method getUrl (line 252) | public function getUrl($path, $params = [])
method setHttpClient (line 277) | public function setHttpClient($httpClient)
method setOptions (line 295) | public function setOptions($options)
method ifDebug (line 326) | private function ifDebug($param)
method setupEndpoints (line 334) | private function setupEndpoints()
method getMessageFactory (line 342) | private function getMessageFactory()
method setMessageFactory (line 356) | public function setMessageFactory(RequestFactory $messageFactory)
FILE: lib/SparkPost/SparkPostException.php
class SparkPostException (line 7) | class SparkPostException extends \Exception
method __construct (line 24) | public function __construct(\Exception $exception, $request = null)
method getRequest (line 44) | public function getRequest()
method getBody (line 54) | public function getBody()
FILE: lib/SparkPost/SparkPostPromise.php
class SparkPostPromise (line 7) | class SparkPostPromise implements HttpPromise
method __construct (line 24) | public function __construct(HttpPromise $promise, $request = null)
method then (line 36) | public function then(callable $onFulfilled = null, callable $onRejecte...
method getState (line 56) | public function getState()
method wait (line 70) | public function wait($unwrap = true)
FILE: lib/SparkPost/SparkPostResponse.php
class SparkPostResponse (line 8) | class SparkPostResponse implements ResponseInterface
method __construct (line 25) | public function __construct(ResponseInterface $response, $request = null)
method getRequest (line 36) | public function getRequest()
method getBody (line 46) | public function getBody()
method getProtocolVersion (line 59) | public function getProtocolVersion()
method withProtocolVersion (line 64) | public function withProtocolVersion($version)
method getHeaders (line 69) | public function getHeaders()
method hasHeader (line 74) | public function hasHeader($name)
method getHeader (line 79) | public function getHeader($name)
method getHeaderLine (line 84) | public function getHeaderLine($name)
method withHeader (line 89) | public function withHeader($name, $value)
method withAddedHeader (line 94) | public function withAddedHeader($name, $value)
method withoutHeader (line 99) | public function withoutHeader($name)
method withBody (line 104) | public function withBody(StreamInterface $body)
method getStatusCode (line 109) | public function getStatusCode()
method withStatus (line 114) | public function withStatus($code, $reasonPhrase = '')
method getReasonPhrase (line 119) | public function getReasonPhrase()
FILE: lib/SparkPost/Transmission.php
class Transmission (line 5) | class Transmission extends ResourceBase
method __construct (line 7) | public function __construct(SparkPost $sparkpost)
method post (line 17) | public function post($payload = [], $headers = [])
method formatPayload (line 33) | public function formatPayload($payload)
method formatBlindCarbonCopy (line 49) | private function formatBlindCarbonCopy($payload)
method formatCarbonCopy (line 67) | private function formatCarbonCopy($payload)
method formatShorthandRecipients (line 93) | private function formatShorthandRecipients($payload)
method addListToRecipients (line 114) | private function addListToRecipients($payload, $listName)
method toAddressObject (line 142) | private function toAddressObject($address)
method toAddressString (line 168) | private function toAddressString($address)
method isEmail (line 188) | private function isEmail($email)
FILE: test/unit/SparkPostResponseTest.php
class SparkPostResponseTest (line 9) | class SparkPostResponseTest extends TestCase
method setUp (line 16) | public function setUp(): void
method testGetProtocolVersion (line 22) | public function testGetProtocolVersion()
method testWithProtocolVersion (line 29) | public function testWithProtocolVersion()
method testGetHeaders (line 38) | public function testGetHeaders()
method testHasHeader (line 45) | public function testHasHeader()
method testGetHeader (line 54) | public function testGetHeader()
method testGetHeaderLine (line 63) | public function testGetHeaderLine()
method testWithHeader (line 72) | public function testWithHeader()
method testWithAddedHeader (line 82) | public function testWithAddedHeader()
method testWithoutHeader (line 92) | public function testWithoutHeader()
method testGetRequest (line 101) | public function testGetRequest()
method testWithBody (line 109) | public function testWithBody()
method testGetStatusCode (line 118) | public function testGetStatusCode()
method testWithStatus (line 125) | public function testWithStatus()
method testGetReasonPhrase (line 134) | public function testGetReasonPhrase()
FILE: test/unit/SparkPostTest.php
class SparkPostTest (line 17) | class SparkPostTest extends TestCase
method setUp (line 47) | public function setUp(): void
method tearDown (line 84) | public function tearDown(): void
method testRequestSync (line 89) | public function testRequestSync()
method testRequestAsync (line 97) | public function testRequestAsync()
method testDebugOptionWhenFalse (line 106) | public function testDebugOptionWhenFalse() {
method testDebugOptionWhenTrue (line 115) | public function testDebugOptionWhenTrue() {
method testSuccessfulSyncRequest (line 135) | public function testSuccessfulSyncRequest()
method testUnsuccessfulSyncRequest (line 148) | public function testUnsuccessfulSyncRequest()
method testSuccessfulSyncRequestWithRetries (line 163) | public function testSuccessfulSyncRequestWithRetries()
method testUnsuccessfulSyncRequestWithRetries (line 176) | public function testUnsuccessfulSyncRequestWithRetries()
method testSuccessfulAsyncRequestWithWait (line 192) | public function testSuccessfulAsyncRequestWithWait()
method testUnsuccessfulAsyncRequestWithWait (line 203) | public function testUnsuccessfulAsyncRequestWithWait()
method testSuccessfulAsyncRequestWithThen (line 217) | public function testSuccessfulAsyncRequestWithThen()
method testUnsuccessfulAsyncRequestWithThen (line 231) | public function testUnsuccessfulAsyncRequestWithThen()
method testSuccessfulAsyncRequestWithRetries (line 245) | public function testSuccessfulAsyncRequestWithRetries()
method testUnsuccessfulAsyncRequestWithRetries (line 266) | public function testUnsuccessfulAsyncRequestWithRetries()
method testPromise (line 285) | public function testPromise()
method testUnsupportedAsyncRequest (line 296) | public function testUnsupportedAsyncRequest()
method testGetHttpHeaders (line 305) | public function testGetHttpHeaders()
method testGetUrl (line 319) | public function testGetUrl()
method testSetHttpClient (line 326) | public function testSetHttpClient()
method testSetHttpAsyncClient (line 333) | public function testSetHttpAsyncClient()
method testSetHttpClientException (line 340) | public function testSetHttpClientException()
method testSetOptionsStringKey (line 347) | public function testSetOptionsStringKey()
method testSetBadOptions (line 354) | public function testSetBadOptions()
method testSetMessageFactory (line 362) | public function testSetMessageFactory()
FILE: test/unit/TransmissionTest.php
class TransmissionTest (line 9) | class TransmissionTest extends TestCase
method setUp (line 55) | public function setUp(): void
method tearDown (line 63) | public function tearDown(): void
method testInvalidEmailFormat (line 68) | public function testInvalidEmailFormat()
method testGet (line 79) | public function testGet()
method testPut (line 101) | public function testPut()
method testPost (line 123) | public function testPost()
method testPostWithRecipientList (line 145) | public function testPostWithRecipientList()
method testDelete (line 170) | public function testDelete()
method testFormatPayload (line 192) | public function testFormatPayload()
Condensed preview — 39 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (107K chars).
[
{
"path": ".coveralls.yml",
"chars": 99,
"preview": "# single file\ncoverage_clover: test/output/clover.xml\njson_path: test/output/coveralls-upload.json\n"
},
{
"path": ".editorconfig",
"chars": 234,
"preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\ntrim_"
},
{
"path": ".travis.yml",
"chars": 420,
"preview": "language: php\nphp:\n - '7.2'\n - '7.3'\n - '7.4'\n - '8.0'\ninstall:\n - composer install --no-interaction\nscript:\n - mk"
},
{
"path": "AUTHORS.md",
"chars": 879,
"preview": "php-sparkpost is maintained by Message Systems.\n\n# Contributors\n\n* Jordan Nornhold, [@beardyman](https://github.com/bear"
},
{
"path": "CHANGELOG.md",
"chars": 6442,
"preview": "# Change Log\nAll notable changes to this project will be documented in this file.\nThis project adheres to [Semantic Vers"
},
{
"path": "CONTRIBUTING.md",
"chars": 4174,
"preview": "# Contributing to php-sparkpost\nTransparency is one of our core values, and we encourage developers to contribute and be"
},
{
"path": "LICENSE.txt",
"chars": 1080,
"preview": "Copyright 2014 Message Systems, Inc. or its affiliates.\n\nPermission is hereby granted, free of charge, to any person obt"
},
{
"path": "MIGRATION.md",
"chars": 3280,
"preview": "# Migration Guide\n\nThis is a guide to help you make the switch when the SparkPost PHP library changes major versions.\n\n#"
},
{
"path": "README.md",
"chars": 12446,
"preview": "<a href=\"https://www.sparkpost.com\"><img src=\"https://www.sparkpost.com/sites/default/files/attachments/SparkPost_Logo_2"
},
{
"path": "composer.json",
"chars": 943,
"preview": "{\n \"name\": \"sparkpost/sparkpost\",\n \"description\": \"Client library for interfacing with the SparkPost API.\",\n \"license"
},
{
"path": "examples/bootstrap.php",
"chars": 65,
"preview": "<?php\n\nrequire_once dirname(__FILE__).'/../vendor/autoload.php';\n"
},
{
"path": "examples/debug/index.php",
"chars": 892,
"preview": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse Guzzl"
},
{
"path": "examples/message-events/get_message_events.php",
"chars": 745,
"preview": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse Guzzl"
},
{
"path": "examples/message-events/get_message_events_with_retry_logic.php",
"chars": 930,
"preview": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse Guzzl"
},
{
"path": "examples/templates/create_template.php",
"chars": 1564,
"preview": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse Guzzl"
},
{
"path": "examples/templates/delete_template.php",
"chars": 691,
"preview": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse Guzzl"
},
{
"path": "examples/templates/get_all_templates.php",
"chars": 635,
"preview": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse Guzzl"
},
{
"path": "examples/templates/get_template.php",
"chars": 699,
"preview": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse Guzzl"
},
{
"path": "examples/templates/preview_template.php",
"chars": 785,
"preview": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse Guzzl"
},
{
"path": "examples/templates/update_template.php",
"chars": 752,
"preview": "<?php\n\nnamespace Examples\\Templates;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse Guzzl"
},
{
"path": "examples/transmissions/create_transmission.php",
"chars": 1424,
"preview": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse G"
},
{
"path": "examples/transmissions/create_transmission_with_attachment.php",
"chars": 1803,
"preview": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse G"
},
{
"path": "examples/transmissions/create_transmission_with_cc_and_bcc.php",
"chars": 1909,
"preview": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse G"
},
{
"path": "examples/transmissions/create_transmission_with_recipient_list.php",
"chars": 1377,
"preview": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse G"
},
{
"path": "examples/transmissions/create_transmission_with_template.php",
"chars": 1108,
"preview": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse G"
},
{
"path": "examples/transmissions/delete_transmission.php",
"chars": 845,
"preview": "<?php\n\nnamespace Examples\\Transmissions;\n\nrequire dirname(__FILE__).'/../bootstrap.php';\n\nuse SparkPost\\SparkPost;\nuse G"
},
{
"path": "examples/transmissions/get_all_transmissions.php",
"chars": 147,
"preview": "<?php\n// Feature has been deprecated\n// See https://developers.sparkpost.com/api/transmissions/#transmissions-get-retrie"
},
{
"path": "examples/transmissions/get_transmission.php",
"chars": 147,
"preview": "<?php\n// Feature has been deprecated\n// See https://developers.sparkpost.com/api/transmissions/#transmissions-get-retrie"
},
{
"path": "lib/SparkPost/Resource.php",
"chars": 169,
"preview": "<?php\n\nnamespace SparkPost;\n\n/**\n * Class Resource.\n *\n * @deprecated Soft reservations placed on name Resource (as of P"
},
{
"path": "lib/SparkPost/ResourceBase.php",
"chars": 2243,
"preview": "<?php\n\nnamespace SparkPost;\n\n/**\n * Class ResourceBase.\n */\nclass ResourceBase\n{\n /**\n * SparkPost object used to"
},
{
"path": "lib/SparkPost/SparkPost.php",
"chars": 10711,
"preview": "<?php\n\nnamespace SparkPost;\n\nuse Http\\Client\\HttpClient;\nuse Http\\Client\\HttpAsyncClient;\nuse Http\\Discovery\\MessageFact"
},
{
"path": "lib/SparkPost/SparkPostException.php",
"chars": 1386,
"preview": "<?php\n\nnamespace SparkPost;\n\nuse Http\\Client\\Exception\\HttpException as HttpException;\n\nclass SparkPostException extends"
},
{
"path": "lib/SparkPost/SparkPostPromise.php",
"chars": 2155,
"preview": "<?php\n\nnamespace SparkPost;\n\nuse Http\\Promise\\Promise as HttpPromise;\n\nclass SparkPostPromise implements HttpPromise\n{\n "
},
{
"path": "lib/SparkPost/SparkPostResponse.php",
"chars": 2670,
"preview": "<?php\n\nnamespace SparkPost;\n\nuse Psr\\Http\\Message\\ResponseInterface as ResponseInterface;\nuse Psr\\Http\\Message\\StreamInt"
},
{
"path": "lib/SparkPost/Transmission.php",
"chars": 6452,
"preview": "<?php\n\nnamespace SparkPost;\n\nclass Transmission extends ResourceBase\n{\n public function __construct(SparkPost $sparkp"
},
{
"path": "phpunit.xml.dist",
"chars": 881,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" backupGlobals=\"fal"
},
{
"path": "test/unit/SparkPostResponseTest.php",
"chars": 5481,
"preview": "<?php\n\nnamespace SparkPost\\Test;\n\nuse PHPUnit\\Framework\\TestCase;\nuse SparkPost\\SparkPostResponse;\nuse Mockery;\n\nclass S"
},
{
"path": "test/unit/SparkPostTest.php",
"chars": 14739,
"preview": "<?php\n\nnamespace SparkPost\\Test;\n\nuse Http\\Client\\HttpAsyncClient;\nuse Http\\Client\\HttpClient;\nuse Http\\Message\\MessageF"
},
{
"path": "test/unit/TransmissionTest.php",
"chars": 7321,
"preview": "<?php\n\nnamespace SparkPost\\Test;\n\nuse PHPUnit\\Framework\\TestCase;\nuse SparkPost\\SparkPost;\nuse Mockery;\n\nclass Transmiss"
}
]
About this extraction
This page contains the full source code of the SparkPost/php-sparkpost GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 39 files (98.4 KB), approximately 26.2k tokens, and a symbol index with 116 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.