├── .env ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── docker-compose.yml ├── docker-nginx-config └── default.conf ├── phpunit.xml.dist ├── samples ├── addWithDupCheck.php ├── resthookManager.php ├── taskManager.php └── verifyRestHook.php ├── src ├── Infusionsoft │ ├── Api │ │ ├── APIEmailService.php │ │ ├── AbstractApi.php │ │ ├── AffiliateProgramService.php │ │ ├── AffiliateService.php │ │ ├── ContactService.php │ │ ├── CreditCardSubmissionService.php │ │ ├── DataService.php │ │ ├── DiscountService.php │ │ ├── FileService.php │ │ ├── FunnelService.php │ │ ├── InvoiceService.php │ │ ├── OrderService.php │ │ ├── ProductService.php │ │ ├── Rest │ │ │ ├── AppointmentService.php │ │ │ ├── CampaignService.php │ │ │ ├── CompanyService.php │ │ │ ├── ContactService.php │ │ │ ├── CustomFieldService.php │ │ │ ├── EmailService.php │ │ │ ├── FileService.php │ │ │ ├── MerchantService.php │ │ │ ├── NoteService.php │ │ │ ├── OpportunityService.php │ │ │ ├── OrderService.php │ │ │ ├── ProductService.php │ │ │ ├── RestModel.php │ │ │ ├── ResthookService.php │ │ │ ├── SubscriptionService.php │ │ │ ├── TagService.php │ │ │ ├── TaskService.php │ │ │ ├── Traits │ │ │ │ ├── CannotCreate.php │ │ │ │ ├── CannotDelete.php │ │ │ │ ├── CannotFind.php │ │ │ │ ├── CannotList.php │ │ │ │ ├── CannotModel.php │ │ │ │ ├── CannotSave.php │ │ │ │ ├── CannotSync.php │ │ │ │ └── CannotWhere.php │ │ │ ├── TransactionService.php │ │ │ └── UserInfoService.php │ │ ├── SearchService.php │ │ ├── ShippingService.php │ │ ├── WebFormService.php │ │ └── WebTrackingService.php │ ├── AuthenticationType.php │ ├── FrameworkSupport │ │ ├── Laravel │ │ │ ├── InfusionsoftFacade.php │ │ │ ├── InfusionsoftServiceProvider.php │ │ │ └── config │ │ │ │ └── config.php │ │ └── Lumen │ │ │ └── InfusionsoftServiceProvider.php │ ├── Http │ │ ├── ArrayLogger.php │ │ ├── ClientInterface.php │ │ ├── GuzzleHttpClient.php │ │ ├── HttpException.php │ │ ├── InfusionsoftHttpAdapterTransport.php │ │ ├── InfusionsoftSerializer.php │ │ └── SerializerInterface.php │ ├── Infusionsoft.php │ ├── InfusionsoftCollection.php │ ├── InfusionsoftException.php │ ├── Token.php │ └── TokenExpiredException.php └── cacert.pem └── tests ├── Infusionsoft ├── InfusionsoftTest.php ├── RestModelTest.php └── TokenTest.php └── bootstrap.php /.env: -------------------------------------------------------------------------------- 1 | # Environment variables for Docker-Compose 2 | 3 | # When under Windows WSL2 it may be necessary to define the directory using 4 | # an explicit Windows path. You can un-comment and update this line to point 5 | # to your mapped volume, and the Docker-Compose mapping will pick it up. 6 | 7 | #INFUSIONSOFT_PHP_WORKING_DIR=//c/Users/user.name/repo-directory-path/infusionsoft-php 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /report 3 | /vendor 4 | .idea 5 | .phpunit.result.cache 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.3 5 | - 7.4 6 | 7 | before_script: 8 | - composer self-update 9 | - composer install --prefer-source --no-interaction --dev 10 | 11 | script: ./vendor/bin/phpunit 12 | 13 | matrix: 14 | fast_finish: true 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## 1.0.0-beta2 6 | 7 | - Fixed: InvoiceService::validateCreditCard should pass a single parameter of the arguments as a struct. (#5) 8 | - Added: Created a Token class that stores all information relating to a token. 9 | - Added: Refresh token and end of life now stored alongside the access token. 10 | - Added: `refreshAccessToken()` refreshes the current access token. 11 | - Changed: `getToken()` and `setToken()` are now `getTokenUri()` and `setTokenUri()`. The former function names now get/set the Token object. 12 | - Removed: `getAccessToken()` and `setAccessToken()` are no longer in the `Infusionsoft` class. Use `getToken()` and call the methods on the returned `Token` object. 13 | 14 | ## 1.0.0-beta1 - 2014-05-14 15 | 16 | - Initial release -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This repository is maintained by the Gryffindor team. 2 | # See: https://github.com/orgs/infusionsoft/teams/gryffindor 3 | * @infusionsoft/gryffindor 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/infusionsoft/php-sdk). 6 | 7 | ## Github Issues 8 | 9 | Github Issues should be used for legitimate issues with this SDK. Problems with your Infusionsoft account, questions about policies, or any other API related questions that do not involve an error with the SDK should be directed to https://developer.infusionsoft.com/support/ 10 | 11 | ## Pull Requests 12 | 13 | - **Document any change in behaviour** - Make sure the README and any other relevant documentation are kept up-to-date. 14 | 15 | - **Consider our release cycle** - We try to follow semver. Randomly breaking public APIs is not an option. 16 | 17 | - **Create topic branches** - Don't ask us to pull from your master branch. 18 | 19 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 20 | 21 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. 22 | 23 | 24 | ## Running Tests 25 | 26 | ``` bash 27 | $ phpunit 28 | ``` 29 | 30 | 31 | **Happy coding**! 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This SDK is released under the MIT Licence below. By using this SDK, you are still bound by our End User License Agreement (http://www.infusionsoft.com/legal-stuff/eula). 2 | 3 | Definitions 4 | 5 | "Software" means this software development kit (sdk) contained within this repostiory. (See our End User License Agreement for any questions) 6 | 7 | The MIT License (MIT) 8 | 9 | Copyright (c) 2014 Infusionsoft(R) 10 | 11 | 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: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | 15 | 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Infusionsoft PHP SDK 2 | 3 | > [!WARNING] 4 | > **⚠️ Deprecated** 5 | > This SDK is no longer actively maintained. 6 | > Please migrate to the replacement: [`keap-sdk-php`](https://github.com/infusionsoft/keap-sdk-php), available on [Packagist](https://packagist.org/packages/keap/keap-sdk). 7 | > 8 | > You can use the [Migration guide from infusionsoft/php-sdk](https://github.com/infusionsoft/keap-sdk-php/blob/main/MigrationFromInfusionsoftPhpSdk.md). 9 | 10 | [![Total Downloads](https://poser.pugx.org/infusionsoft/php-sdk/downloads.png)](https://packagist.org/packages/infusionsoft/php-sdk) 11 | [![Latest Stable Version](https://poser.pugx.org/infusionsoft/php-sdk/v/stable.png)](https://packagist.org/packages/infusionsoft/php-sdk) 12 | 13 | 14 | ## Version Notes 15 | 16 | This version implements RESTful endpoints, a new version of Guzzle, and a restructured request handler. 17 | 18 | As of version 1.6, PHP 8.1+ is required. 19 | 20 | ### Breaking Change 21 | 22 | With the Guzzle 7 upgrade, there was a refactor on the `request` function name in Infusionsoft\Http\ClientInterface. If you created a custom HttpClient, you'll need to update to use the new function name of `call` 23 | 24 | If you use the `Contacts`, `Orders` or `Products` services, there are now two different classes handling each service - one for REST, one for XML-RPC. *This version of the SDK will load the REST class by default.* If you still need the XML-RPC class, pass `'xml'` as an argument when requesting the object: `$infusionsoft->orders('xml')'` 25 | 26 | Kudos to [toddstoker](https://github.com/toddstoker) and [mattmerrill](https://github.com/mattmerrill) for their contributions to this release. 27 | 28 | ## Install 29 | 30 | Using the composer CLI: 31 | 32 | ``` 33 | composer require infusionsoft/php-sdk 34 | ``` 35 | 36 | Or manually add it to your composer.json: 37 | 38 | ``` json 39 | { 40 | "require": { 41 | "infusionsoft/php-sdk": "1.6.*" 42 | } 43 | } 44 | ``` 45 | 46 | ## Authentication 47 | 48 | Currently Keap supports two types of authentication for our APIs: the OAuth2 Access Code Grant and API Keys. 49 | Developers of third-party integrations should always use our OAuth2 authentication, but developers building integrations for a single tenant may find the use of API Keys much simpler. 50 | 51 | ### OAuth2 Access Code Grant 52 | 53 | The client ID and secret are the key and secret for your OAuth2 application found at the [Infusionsoft Developers](https://keys.developer.keap.com) website. 54 | 55 | ```php 56 | 57 | if(empty(session_id();)) session_start(); 58 | 59 | require_once 'vendor/autoload.php'; 60 | 61 | $infusionsoft = new \Infusionsoft\Infusionsoft(array( 62 | 'clientId' => 'XXXXXXXXXXXXXXXXXXXXXXXX', 63 | 'clientSecret' => 'XXXXXXXXXX', 64 | 'redirectUri' => 'http://example.com/', 65 | )); 66 | 67 | // If the serialized token is available in the session storage, we tell the SDK 68 | // to use that token for subsequent requests. 69 | if (isset($_SESSION['token'])) { 70 | $infusionsoft->setToken(unserialize($_SESSION['token'])); 71 | } 72 | 73 | // If we are returning from Infusionsoft we need to exchange the code for an 74 | // access token. 75 | if (isset($_GET['code']) and !$infusionsoft->getToken()) { 76 | $_SESSION['token'] = serialize($infusionsoft->requestAccessToken($_GET['code'])); 77 | } 78 | 79 | if ($infusionsoft->getToken()) { 80 | // Save the serialized token to the current session for subsequent requests 81 | $_SESSION['token'] = serialize($infusionsoft->getToken()); 82 | 83 | // MAKE INFUSIONSOFT REQUEST 84 | } else { 85 | echo 'Click here to authorize'; 86 | } 87 | ``` 88 | 89 | ### API Keys 90 | 91 | API Keys are a "password" for your data in an application and should always be treated like a dangerous secret. 92 | 93 | In our UI you will find an API Settings screen which divides API Keys into two distinct categories: 94 | * `Personal Access Tokens`, which are scoped to your own user account and can only see and manipulate the data you have access to. 95 | * `Service Account Keys`, which can only be authorized by an Administrator and have full access to the data stored in the application. 96 | 97 | For additional information on how to authorize and use PATs and SAKs please see our [developer documentation](https://developer.infusionsoft.com/pat-and-sak/). 98 | 99 | ```php 100 | require_once 'vendor/autoload.php'; 101 | 102 | $infusionsoft = new \Infusionsoft\Infusionsoft(array( 103 | 'apikey' => $APIKeyRetrievedFromCredentialStorage, 104 | )); 105 | 106 | // MAKE INFUSIONSOFT REQUEST 107 | ``` 108 | 109 | ## Making XML-RPC Requests 110 | 111 | ```php 112 | require_once 'vendor/autoload.php'; 113 | 114 | // 115 | // Setup your Infusionsoft object here, then set your token either via the request or from storage 116 | // As of v1.3 contacts defaults to rest 117 | $infusionsoft->setToken($myTokenObject); 118 | 119 | $infusionsoft->contacts('xml')->add(array('FirstName' => 'John', 'LastName' => 'Doe')); 120 | 121 | ``` 122 | 123 | ## Making REST Requests 124 | 125 | The PHP SDK is setup to allow easy access to REST endpoints. In general, a single result is returned as a Class representing 126 | that object, and multiple objects are returned as an Infusionsoft Collection, which is simply a wrapper around an array 127 | of results making them easier to manage. 128 | 129 | The standard REST operations are mapped to a series of simple functions. We'll use the Tasks service for our examples, 130 | but the operations below work on all documented Infusionsoft REST services. 131 | 132 | To retrieve all tasks: 133 | 134 | ```php 135 | $tasks = $infusionsoft->tasks()->all(); 136 | ``` 137 | 138 | To retrieve a single task: 139 | 140 | ```php 141 | $task = $infusionsoft->tasks()->find($taskId); 142 | ``` 143 | 144 | To query only completed tasks: 145 | 146 | ```php 147 | $tasks = $infusionsoft->tasks()->where('status', 'completed')->get(); 148 | ``` 149 | 150 | You can chain `where()` as many times as you'd like, or you can pass an array: 151 | 152 | ```php 153 | $tasks = $infusionsoft->tasks()->where(['status' => 'completed', 'user_id' => '45'])->get(); 154 | ``` 155 | 156 | To create a task: 157 | ```php 158 | $task = $infusionsoft->tasks()->create([ 159 | 'title' => 'My First Task', 160 | 'description' => 'Better get it done!' 161 | ]); 162 | ``` 163 | 164 | Then update that task: 165 | ```php 166 | $task->title = 'A better task title'; 167 | $task->save(); 168 | ``` 169 | 170 | And finally, to delete the task: 171 | ```php 172 | $task->delete(); 173 | ``` 174 | 175 | Several REST services have a `/sync` endpoint, which we provide a helper method for: 176 | ```php 177 | $tasks = $infusionsoft->tasks()->sync($syncId); 178 | ``` 179 | 180 | This returns a list of tasks created or updated since the sync ID was last generated. 181 | 182 | 183 | ```php 184 | require_once 'vendor/autoload.php'; 185 | 186 | // 187 | // Setup your Infusionsoft object here, then set your token either via the request or from storage 188 | // 189 | $infusionsoft->setToken($myTokenObject); 190 | 191 | $infusionsoft->tasks()->find('1'); 192 | 193 | ``` 194 | 195 | 196 | ### Dates 197 | 198 | DateTime objects are used instead of a DateTime string where the date(time) is a parameter in the method. 199 | 200 | ```php 201 | $datetime = new \DateTime('now',new \DateTimeZone('America/New_York')); 202 | ``` 203 | 204 | ### Debugging 205 | 206 | To enable debugging of requests and responses, you need to set the debug flag to try by using: 207 | 208 | ```php 209 | $infusionsoft->setDebug(true); 210 | ``` 211 | 212 | Once enabled, logs will by default be written to an array that can be accessed by: 213 | 214 | ```php 215 | $infusionsoft->getLogs(); 216 | ``` 217 | 218 | You can utilize the powerful logging plugin built into Guzzle by using one of the available adapters. For example, to use the Monolog writer to write to a file: 219 | 220 | ```php 221 | use Monolog\Handler\StreamHandler; 222 | use Monolog\Logger; 223 | 224 | $logger = new Logger('client'); 225 | $logger->pushHandler(new StreamHandler('infusionsoft.log')); 226 | 227 | $infusionsoft->setHttpLogAdapter($logger); 228 | ``` 229 | 230 | ## Testing 231 | 232 | ``` bash 233 | $ phpunit 234 | ``` 235 | 236 | ## Laravel Framework Support 237 | 238 | ### Laravel < 5.5 239 | 240 | In config/app.php, register the service provider 241 | 242 | ``` 243 | Infusionsoft\FrameworkSupport\Laravel\InfusionsoftServiceProvider::class, 244 | ``` 245 | 246 | Register the Facade (optional) 247 | 248 | ``` 249 | 'Infusionsoft' => Infusionsoft\FrameworkSupport\Laravel\InfusionsoftFacade::class 250 | ``` 251 | 252 | ### Laravel >= 5.5 253 | 254 | In Laravel 5.5, package auto-discovery was added. The service provider and facade will be detected for you. Continue by publishing the vendor assets and adding your env variables. 255 | 256 | Publish the config 257 | 258 | ``` 259 | php artisan vendor:publish --provider="Infusionsoft\FrameworkSupport\Laravel\InfusionsoftServiceProvider" 260 | ``` 261 | 262 | Set your env variables 263 | 264 | ``` 265 | INFUSIONSOFT_CLIENT_ID=xxxxxxxx 266 | INFUSIONSOFT_SECRET=xxxxxxxx 267 | INFUSIONSOFT_REDIRECT_URL=http://localhost/auth/callback 268 | ``` 269 | 270 | Access Infusionsoft from the Facade or Binding 271 | 272 | ``` 273 | $data = Infusionsoft::data()->query("Contact",1000,0,['Id' => '123'],['Id','FirstName','LastName','Email'], 'Id', false); 274 | 275 | $data = app('infusionsoft')->data()->query("Contact",1000,0,['Id' => '123'],['Id','FirstName','LastName','Email'], 'Id', false); 276 | ``` 277 | 278 | ## Lumen Service Provider 279 | 280 | In bootstrap/app.php, register the service provider 281 | 282 | ``` 283 | $app->register(Infusionsoft\FrameworkSupport\Lumen\InfusionsoftServiceProvider::class); 284 | ``` 285 | 286 | Set your env variables (make sure you're loading your env file in app.php) 287 | 288 | ``` 289 | INFUSIONSOFT_CLIENT_ID=xxxxxxxx 290 | INFUSIONSOFT_SECRET=xxxxxxxx 291 | INFUSIONSOFT_REDIRECT_URL=http://localhost/auth/callback 292 | ``` 293 | 294 | Access Infusionsoft from the Binding 295 | 296 | ``` 297 | $data = app('infusionsoft')->data()->query("Contact",1000,0,['Id' => '123'],['Id','FirstName','LastName','Email'], 'Id', false); 298 | ``` 299 | 300 | ## SDK Development 301 | You can install the Composer dependencies without installing Composer: 302 | ``` 303 | docker compose run composer 304 | ``` 305 | 306 | You can access the samples by spinning up the Docker container for the Composer dependencies: 307 | ``` 308 | docker compose up -d 309 | ``` 310 | 311 | Tests can be executed without installing PHP in the host environment (while the main container is running): 312 | ``` 313 | docker exec -it infusionsoft-php /var/www/html/vendor/bin/phpunit tests 314 | ``` 315 | 316 | If using Docker for Windows, please see `.env` for additional details. 317 | ## Contributing 318 | 319 | Please see [CONTRIBUTING](https://github.com/infusionsoft/infusionsoft-php/blob/master/CONTRIBUTING.md) for details. 320 | 321 | 322 | ## License 323 | 324 | The MIT License (MIT). Please see [License File](https://github.com/infusionsoft/infusionsoft-php/blob/master/LICENSE) for more information. 325 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "infusionsoft/php-sdk", 3 | "description": "PHP SDK for the Infusionsoft", 4 | "keywords": [ 5 | "infusionsoft", 6 | "sdk" 7 | ], 8 | "homepage": "https://developer.infusionsoft.com", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Infusionsoft", 13 | "homepage": "https://developer.infusionsoft.com" 14 | } 15 | ], 16 | "require": { 17 | "php": ">=8.1", 18 | "guzzlehttp/guzzle": "^7.4.2", 19 | "lstrojny/fxmlrpc": "^0.22.0", 20 | "psr/log": "^1.0|^2.0|^3.0", 21 | "laminas/laminas-diactoros": "^3.5.0", 22 | "php-http/guzzle7-adapter": "^1.0", 23 | "php-http/message": "^1.16", 24 | "psr/http-factory": "^1.0" 25 | }, 26 | "require-dev": { 27 | "mockery/mockery": "^1.2", 28 | "phpunit/phpunit": "~9", 29 | "doctrine/instantiator": "^1.3.0", 30 | "squizlabs/php_codesniffer": "3.*" 31 | }, 32 | "autoload": { 33 | "psr-0": { 34 | "Infusionsoft": ["src", "tests"] 35 | } 36 | }, 37 | "extra": { 38 | "laravel": { 39 | "providers": [ 40 | "Infusionsoft\\FrameworkSupport\\Laravel\\InfusionsoftServiceProvider" 41 | ], 42 | "aliases": { 43 | "Infusionsoft": "Infusionsoft\\FrameworkSupport\\Laravel\\InfusionsoftFacade" 44 | } 45 | } 46 | }, 47 | "config": { 48 | "allow-plugins": { 49 | "php-http/discovery": true 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.3" 2 | services: 3 | 4 | web: 5 | image: nginx:latest 6 | container_name: infusionsoft-php-nginx 7 | ports: 8 | - "80:80" 9 | volumes: 10 | - "${INFUSIONSOFT_PHP_WORKING_DIR-.}:/var/www/html" 11 | - "${INFUSIONSOFT_PHP_WORKING_DIR-.}/docker-nginx-config:/etc/nginx/conf.d" 12 | links: 13 | - php 14 | 15 | php: 16 | image: php:8.1-fpm 17 | container_name: infusionsoft-php 18 | volumes: 19 | - "${INFUSIONSOFT_PHP_WORKING_DIR-.}:/var/www/html" 20 | 21 | composer: 22 | image: composer:latest 23 | volumes: 24 | - ${INFUSIONSOFT_PHP_WORKING_DIR-.}:/app 25 | command: "composer install --optimize-autoloader --no-interaction --no-progress" 26 | profiles: ["install"] 27 | -------------------------------------------------------------------------------- /docker-nginx-config/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | listen [::]:80; 4 | server_name localhost; 5 | 6 | index index.php index.html; 7 | error_log /var/log/nginx/error.log; 8 | access_log /var/log/nginx/access.log; 9 | root /var/www/html; 10 | 11 | location ~ \.php$ { 12 | try_files $uri =404; 13 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 14 | fastcgi_pass php:9000; 15 | fastcgi_index index.php; 16 | include fastcgi_params; 17 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 18 | fastcgi_param PATH_INFO $fastcgi_path_info; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | src/Infusionsoft 6 | 7 | 8 | 9 | 10 | tests/Infusionsoft 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /samples/addWithDupCheck.php: -------------------------------------------------------------------------------- 1 | '', 9 | 'clientSecret' => '', 10 | 'redirectUri' => '', 11 | )); 12 | 13 | // If the serialized token is available in the session storage, we tell the SDK 14 | // to use that token for subsequent requests. 15 | if (isset($_SESSION['token'])) { 16 | $infusionsoft->setToken(unserialize($_SESSION['token'])); 17 | } 18 | 19 | // If we are returning from Infusionsoft we need to exchange the code for an 20 | // access token. 21 | if (isset($_GET['code']) and !$infusionsoft->getToken()) { 22 | $infusionsoft->requestAccessToken($_GET['code']); 23 | 24 | // Save the serialized token to the current session for subsequent requests 25 | $_SESSION['token'] = serialize($infusionsoft->getToken()); 26 | } 27 | 28 | function add($infusionsoft, $email) 29 | { 30 | $email1 = new \stdClass; 31 | $email1->field = 'EMAIL1'; 32 | $email1->email = $email; 33 | $contact = ['given_name' => 'John', 'family_name' => 'Doe', 'email_addresses' => [$email1]]; 34 | 35 | return $infusionsoft->contacts()->create($contact); 36 | } 37 | 38 | if ($infusionsoft->getToken()) { 39 | try { 40 | 41 | $email = 'john.doe4@example.com'; 42 | 43 | try { 44 | $cid = $infusionsoft->contacts()->where('email', $email)->first(); 45 | } catch (\Infusionsoft\InfusionsoftException $e) { 46 | $cid = add($infusionsoft, $email); 47 | } 48 | 49 | } catch (\Infusionsoft\TokenExpiredException $e) { 50 | // If the request fails due to an expired access token, we can refresh 51 | // the token and then do the request again. 52 | $infusionsoft->refreshAccessToken(); 53 | 54 | $cid = add($infusionsoft); 55 | } 56 | 57 | $contact = $infusionsoft->contacts()->with('custom_fields')->find($cid->id); 58 | 59 | var_dump($contact->toArray()); 60 | 61 | // Save the serialized token to the current session for subsequent requests 62 | $_SESSION['token'] = serialize($infusionsoft->getToken()); 63 | } else { 64 | echo 'Click here to authorize'; 65 | } 66 | -------------------------------------------------------------------------------- /samples/resthookManager.php: -------------------------------------------------------------------------------- 1 | '', 10 | 'clientSecret' => '', 11 | 'redirectUri' => '', 12 | )); 13 | 14 | // If the serialized token is available in the session storage, we tell the SDK 15 | // to use that token for subsequent requests. 16 | if (isset($_SESSION['token'])) { 17 | $infusionsoft->setToken(unserialize($_SESSION['token'])); 18 | } 19 | 20 | // If we are returning from Infusionsoft we need to exchange the code for an 21 | // access token. 22 | if (isset($_GET['code']) and !$infusionsoft->getToken()) { 23 | $infusionsoft->requestAccessToken($_GET['code']); 24 | $_SESSION['token'] = serialize($infusionsoft->getToken()); 25 | } 26 | 27 | function resthookManager($infusionsoft) { 28 | $resthooks = $infusionsoft->resthooks(); 29 | 30 | // first, create a new task 31 | $resthook = $resthooks->create([ 32 | 'eventKey' => 'contact.add', 33 | 'hookUrl' => 'http://infusionsoft.app/verifyRestHook.php' 34 | ]); 35 | var_dump($resthook); 36 | $resthook = $resthooks->find($resthook->id)->verify(); 37 | 38 | return $resthook; 39 | } 40 | 41 | if ($infusionsoft->getToken()) { 42 | try { 43 | $resthook = resthookManager($infusionsoft); 44 | } 45 | catch (\Infusionsoft\TokenExpiredException $e) { 46 | // If the request fails due to an expired access token, we can refresh 47 | // the token and then do the request again. 48 | $infusionsoft->refreshAccessToken(); 49 | 50 | // Save the serialized token to the current session for subsequent requests 51 | $_SESSION['token'] = serialize($infusionsoft->getToken()); 52 | 53 | $resthook = resthookManager($infusionsoft); 54 | } 55 | 56 | var_dump($resthook); 57 | } 58 | else { 59 | echo 'Click here to authorize'; 60 | } 61 | -------------------------------------------------------------------------------- /samples/taskManager.php: -------------------------------------------------------------------------------- 1 | '', 9 | 'clientSecret' => '', 10 | 'redirectUri' => '', 11 | )); 12 | 13 | // If the serialized token is available in the session storage, we tell the SDK 14 | // to use that token for subsequent requests. 15 | if (isset($_SESSION['token'])) { 16 | $infusionsoft->setToken(unserialize($_SESSION['token'])); 17 | } 18 | 19 | // If we are returning from Infusionsoft we need to exchange the code for an 20 | // access token. 21 | if (isset($_GET['code']) and !$infusionsoft->getToken()) { 22 | $infusionsoft->requestAccessToken($_GET['code']); 23 | 24 | // Save the serialized token to the current session for subsequent requests 25 | $_SESSION['token'] = serialize($infusionsoft->getToken()); 26 | } 27 | 28 | function taskManager($infusionsoft) { 29 | $tasks = $infusionsoft->tasks(); 30 | 31 | // first, create a new task 32 | $task = $tasks->create([ 33 | 'title' => 'Test Task', 34 | 'description' => 'This is the task description' 35 | ]); 36 | 37 | // oops, we wanted a different title 38 | $task->title = 'Real Test Task'; 39 | $task->save(); 40 | 41 | return $task; 42 | } 43 | 44 | if ($infusionsoft->getToken()) { 45 | try { 46 | $task = taskManager($infusionsoft); 47 | } 48 | catch (\Infusionsoft\TokenExpiredException $e) { 49 | // If the request fails due to an expired access token, we can refresh 50 | // the token and then do the request again. 51 | $infusionsoft->refreshAccessToken(); 52 | 53 | // Save the serialized token to the current session for subsequent requests 54 | $_SESSION['token'] = serialize($infusionsoft->getToken()); 55 | 56 | $task = taskManager($infusionsoft); 57 | } 58 | 59 | var_dump($task); 60 | } 61 | else { 62 | echo 'Click here to authorize'; 63 | } 64 | -------------------------------------------------------------------------------- /samples/verifyRestHook.php: -------------------------------------------------------------------------------- 1 | '', 9 | 'clientSecret' => '', 10 | 'redirectUri' => '', 11 | )); 12 | 13 | // In order to verify the endpoint, we need to return the X-Hook-Secret header. 14 | // By default, the autoverify() function will set the proper header, but if you 15 | // pass false as the first argument to autoverify(false) the function will simply 16 | // return the header value for you to set as you please (handy if you are using 17 | // a PHP class or framework that manages requests for you 18 | 19 | $infusionsoft->resthooks()->autoverify(); 20 | 21 | return; -------------------------------------------------------------------------------- /src/Infusionsoft/Api/APIEmailService.php: -------------------------------------------------------------------------------- 1 | client->request('APIEmailService.addEmailTemplate', $placeTitle, $categories, $fromAddress, $toAddress, $ccAddress, $bccAddress, $subject, $textBody, $htmlBody, $contentType, $mergeContext); 24 | } 25 | 26 | /** 27 | * @param integer $contactId 28 | * @param string $fromName 29 | * @param string $fromAddress 30 | * @param string $toAddress 31 | * @param string $ccAddress 32 | * @param string $bccAddress 33 | * @param string $contentType 34 | * @param string $subject 35 | * @param string $htmlBody 36 | * @param string $textBody 37 | * @param string $header 38 | * @param string $receivedDate 39 | * @param string $sentDate 40 | * @param integer $emailSentType 41 | * @return bool 42 | */ 43 | public function attachEmail($contactId, $fromName, $fromAddress, $toAddress, $ccAddress, $bccAddress, $contentType, $subject, $htmlBody, $textBody, $header, $receivedDate, $sentDate, $emailSentType) 44 | { 45 | return $this->client->request('APIEmailService.attachEmail', $contactId, $fromName, $fromAddress, $toAddress, $ccAddress, $bccAddress, $contentType, $subject, $htmlBody, $textBody, $header, $receivedDate, $sentDate, $emailSentType); 46 | } 47 | 48 | /** 49 | * @param integer $templateId 50 | * @return array 51 | */ 52 | public function getEmailTemplate($templateId) 53 | { 54 | return $this->client->request('APIEmailService.getEmailTemplate', $templateId); 55 | } 56 | 57 | /** 58 | * @param string $email 59 | * @return integer 60 | */ 61 | public function getOptStatus($email) 62 | { 63 | return $this->client->request('APIEmailService.getOptStatus', $email); 64 | } 65 | 66 | /** 67 | * @param string $email 68 | * @param string $optInReason 69 | * @return bool 70 | */ 71 | public function optIn($email, $optInReason) 72 | { 73 | return $this->client->request('APIEmailService.optIn', $email, $optInReason); 74 | } 75 | 76 | /** 77 | * @param string $email 78 | * @param string $optOutReason 79 | * @return bool 80 | */ 81 | public function optOut($email, $optOutReason) 82 | { 83 | return $this->client->request('APIEmailService.optOut', $email, $optOutReason); 84 | } 85 | 86 | /** 87 | * @param string $contactList 88 | * @param string $fromAddress 89 | * @param string $toAddress 90 | * @param string $ccAddress 91 | * @param string $bccAddress 92 | * @param string $contentType 93 | * @param string $subject 94 | * @param string $htmlBody 95 | * @param string $textBody 96 | * @return bool 97 | */ 98 | public function sendEmail($contactList, $fromAddress, $toAddress, $ccAddress, $bccAddress, $contentType, $subject, $htmlBody, $textBody) 99 | { 100 | return $this->client->request('APIEmailService.sendEmail', $contactList, $fromAddress, $toAddress, $ccAddress, $bccAddress, $contentType, $subject, $htmlBody, $textBody); 101 | } 102 | 103 | /** 104 | * @param array $contactList 105 | * @param integer $templateId 106 | * @return bool 107 | */ 108 | public function sendTemplate($contactList, $templateId) 109 | { 110 | return $this->client->request('APIEmailService.sendEmail', $contactList, $templateId); 111 | } 112 | 113 | /** 114 | * @param string $templateId 115 | * @param string $pieceTitle 116 | * @param string $category 117 | * @param string $fromAddress 118 | * @param string $toAddress 119 | * @param string $ccAddress 120 | * @param string $bccAddress 121 | * @param string $subject 122 | * @param string $textBody 123 | * @param string $htmlBody 124 | * @param string $contentType 125 | * @param string $mergeContext 126 | * @return bool 127 | */ 128 | public function updateEmailTemplate($templateId, $pieceTitle, $category, $fromAddress, $toAddress, $ccAddress, $bccAddress, $subject, $textBody, $htmlBody, $contentType, $mergeContext) 129 | { 130 | return $this->client->request('APIEmailService.updateEmailTemplate', $templateId, $pieceTitle, $category, $fromAddress, $toAddress, $ccAddress, $bccAddress, $subject, $textBody, $htmlBody, $contentType, $mergeContext); 131 | } 132 | 133 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/AbstractApi.php: -------------------------------------------------------------------------------- 1 | client->request('AffiliateProgramService.getAffiliatesByProgram', $programId); 14 | } 15 | 16 | /** 17 | * @param integer $affiliateId 18 | * @return array 19 | */ 20 | public function getProgramsForAffiliate($affiliateId) 21 | { 22 | return $this->client->request('AffiliateProgramService.getProgramsForAffiliate', $affiliateId); 23 | } 24 | 25 | /** 26 | * @return array 27 | */ 28 | public function getAffiliatePrograms() 29 | { 30 | return $this->client->request('AffiliateProgramService.getAffiliatePrograms'); 31 | } 32 | 33 | /** 34 | * @param integer $programId 35 | * @return array 36 | */ 37 | public function getResourcesForAffiliateProgram($programId) 38 | { 39 | return $this->client->request('AffiliateProgramService.getResourcesForAffiliateProgram', $programId); 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/AffiliateService.php: -------------------------------------------------------------------------------- 1 | client->request('APIAffiliateService.affClawbacks', $affiliateId, $filterStartDate, $filterEndDate); 16 | } 17 | 18 | /** 19 | * @param integer $affiliateId 20 | * @param string $filterStartDate 21 | * @param string $filterEndDate 22 | * @return array 23 | */ 24 | public function affCommissions($affiliateId, $filterStartDate, $filterEndDate) 25 | { 26 | return $this->client->request('APIAffiliateService.affCommissions', $affiliateId, $filterStartDate, $filterEndDate); 27 | } 28 | 29 | /** 30 | * @param integer $affiliateId 31 | * @return array 32 | */ 33 | public function getRedirectLinksForAffiliate($affiliateId) 34 | { 35 | return $this->client->request('AffiliateService.getRedirectLinksForAffiliate', $affiliateId); 36 | } 37 | 38 | /** 39 | * @param integer $affiliateId 40 | * @param string $filterStartDate 41 | * @param string $filterEndDate 42 | * @return array 43 | */ 44 | public function affPayouts($affiliateId, $filterStartDate, $filterEndDate) 45 | { 46 | return $this->client->request('APIAffiliateService.affPayouts', $affiliateId, $filterStartDate, $filterEndDate); 47 | } 48 | 49 | /** 50 | * @param array $affiliateIds 51 | * @return array 52 | */ 53 | public function affRunningTotals($affiliateIds) 54 | { 55 | return $this->client->request('APIAffiliateService.affRunningTotals', $affiliateIds); 56 | } 57 | 58 | /** 59 | * @param array $affiliateId 60 | * @param string $filterStartDate 61 | * @param string $filterEndDate 62 | * @return array 63 | */ 64 | public function affSummary($affiliateId, $filterStartDate, $filterEndDate) 65 | { 66 | return $this->client->request('APIAffiliateService.affSummary', $affiliateId, $filterStartDate, $filterEndDate); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/ContactService.php: -------------------------------------------------------------------------------- 1 | client->request('ContactService.add', $data); 14 | } 15 | 16 | /** 17 | * @param integer $contactId 18 | * @param integer $duplicateContactId 19 | * @return bool 20 | */ 21 | public function merge($contactId, $duplicateContactId) 22 | { 23 | return $this->client->request('ContactService.merge', $contactId, $duplicateContactId); 24 | } 25 | 26 | /** 27 | * @param integer $contactId 28 | * @param integer $campaignId 29 | * @return bool 30 | */ 31 | public function addToCampaign($contactId, $campaignId) 32 | { 33 | return $this->client->request('ContactService.addToCampaign', $contactId, $campaignId); 34 | } 35 | 36 | /** 37 | * @param integer $contactId 38 | * @param integer $groupId 39 | * @return bool 40 | */ 41 | public function addToGroup($contactId, $groupId) 42 | { 43 | return $this->client->request('ContactService.addToGroup', $contactId, $groupId); 44 | } 45 | 46 | /** 47 | * @param integer $contactId 48 | * @param integer $followUpSequenceId 49 | * @return integer 50 | */ 51 | public function getNextCampaignStep($contactId, $followUpSequenceId) 52 | { 53 | return $this->client->request('ContactService.getNextCampaignStep', $contactId, $followUpSequenceId); 54 | } 55 | 56 | /** 57 | * @param string $email 58 | * @param array $selectedFields 59 | * @return array 60 | */ 61 | public function findByEmail($email, $selectedFields) 62 | { 63 | return $this->client->request('ContactService.findByEmail', $email, $selectedFields); 64 | } 65 | 66 | /** 67 | * @param integer $contactId 68 | * @param array $selectedFields 69 | * @return array 70 | */ 71 | public function load($contactId, $selectedFields) 72 | { 73 | return $this->client->request('ContactService.load', $contactId, $selectedFields); 74 | } 75 | 76 | /** 77 | * @param integer $contactId 78 | * @param integer $sequenceId 79 | * @return bool 80 | */ 81 | public function pauseCampaign($contactId, $sequenceId) 82 | { 83 | return $this->client->request('ContactService.pauseCampaign', $contactId, $sequenceId); 84 | } 85 | 86 | /** 87 | * @param integer $contactId 88 | * @param integer $followUpSequenceId 89 | * @return bool 90 | */ 91 | public function removeFromCampaign($contactId, $followUpSequenceId) 92 | { 93 | return $this->client->request('ContactService.removeFromCampaign', $contactId, $followUpSequenceId); 94 | } 95 | 96 | /** 97 | * @param integer $contactId 98 | * @param integer $tagId 99 | * @return bool 100 | */ 101 | public function removeFromGroup($contactId, $tagId) 102 | { 103 | return $this->client->request('ContactService.removeFromGroup', $contactId, $tagId); 104 | } 105 | 106 | /** 107 | * @param integer $contactId 108 | * @param integer $seqId 109 | * @return integer 110 | */ 111 | public function resumeCampaignForContact($contactId, $seqId) 112 | { 113 | return $this->client->request('ContactService.resumeCampaignForContact', $contactId, $seqId); 114 | } 115 | 116 | /** 117 | * @param array $contactIds 118 | * @param integer $sequenceStepId 119 | * @return integer 120 | */ 121 | public function rescheduleCampaignStep($contactIds, $sequenceStepId) 122 | { 123 | return $this->client->request('ContactService.rescheduleCampaignStep', $contactIds, $sequenceStepId); 124 | } 125 | 126 | /** 127 | * @param integer $contactId 128 | * @param integer $actionSetId 129 | * @return array 130 | */ 131 | public function runActionSequence($contactId, $actionSetId) 132 | { 133 | return $this->client->request('ContactService.runActionSequence', $contactId, $actionSetId); 134 | } 135 | 136 | /** 137 | * @param array $data 138 | * @param string $dupCheckType 139 | * @return integer 140 | */ 141 | public function addWithDupCheck($data, $dupCheckType) 142 | { 143 | return $this->client->request('ContactService.addWithDupCheck', $data, $dupCheckType); 144 | } 145 | 146 | /** 147 | * @param integer $contactId 148 | * @param array $data 149 | * @return integer 150 | */ 151 | public function update($contactId, $data) 152 | { 153 | return $this->client->request('ContactService.update', $contactId, $data); 154 | } 155 | 156 | /** 157 | * @param integer $contactId1 158 | * @param integer $contactId2 159 | * @param integer $linkId 160 | * @return integer 161 | */ 162 | public function linkContacts($contactId1, $contactId2, $linkId) 163 | { 164 | return $this->client->request("ContactService.linkContacts", $contactId1, $contactId2, $linkId); 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/CreditCardSubmissionService.php: -------------------------------------------------------------------------------- 1 | client->request('CreditCardSubmissionService.requestSubmissionToken', $contactId, $successUrl, 14 | $failureURL); 15 | } 16 | 17 | /** 18 | * @param integer $webFormId 19 | * @return mixed 20 | */ 21 | public function requestCreditCardId($token) 22 | { 23 | return $this->client->request('CreditCardSubmissionService.requestCreditCardId', $token); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/DataService.php: -------------------------------------------------------------------------------- 1 | client->request('DataService.add', $table, $values); 15 | } 16 | 17 | /** 18 | * @param string $table 19 | * @param integer $recordId 20 | * @param array $wantedFields 21 | * @return array 22 | */ 23 | public function load($table, $recordId, $wantedFields) 24 | { 25 | return $this->client->request('DataService.load', $table, $recordId, $wantedFields); 26 | } 27 | 28 | /** 29 | * @param string $table 30 | * @param integer $Id 31 | * @param array $values 32 | * @return array 33 | */ 34 | public function update($table, $Id, $values) 35 | { 36 | return $this->client->request('DataService.update', $table, $Id, $values); 37 | } 38 | 39 | /** 40 | * @param string $table 41 | * @param integer $Id 42 | * @return bool 43 | */ 44 | public function delete($table, $Id) 45 | { 46 | return $this->client->request('DataService.delete', $table, $Id); 47 | } 48 | 49 | /** 50 | * @param string $table 51 | * @param integer $limit 52 | * @param integer $page 53 | * @param string $fieldName 54 | * @param string $fieldValue 55 | * @param array $returnFields 56 | * @return array 57 | */ 58 | public function findByField($table, $limit, $page, $fieldName, $fieldValue, $returnFields) 59 | { 60 | return $this->client->request('DataService.findByField', $table, $limit, $page, $fieldName, $fieldValue, $returnFields); 61 | } 62 | 63 | /** 64 | * @param string $table 65 | * @param integer $limit 66 | * @param integer $page 67 | * @param array $queryData 68 | * @param array $selectedFields 69 | * @param string $orderBy 70 | * @param boolean $ascending 71 | * @return array 72 | */ 73 | public function query($table, $limit, $page, $queryData, $selectedFields, $orderBy, $ascending) 74 | { 75 | return $this->client->request('DataService.query', $table, $limit, $page, $queryData, $selectedFields, $orderBy, $ascending); 76 | } 77 | 78 | /** 79 | * @param string $table 80 | * @param array $queryData 81 | * @return integer 82 | */ 83 | public function count($table, $queryData) 84 | { 85 | return $this->client->request('DataService.count', $table, $queryData); 86 | } 87 | 88 | /** 89 | * @param string $customFieldType 90 | * @param string $displayName 91 | * @param string $dataType 92 | * @param integer $headerId 93 | * @return integer 94 | */ 95 | public function addCustomField($customFieldType, $displayName, $dataType, $headerId) 96 | { 97 | return $this->client->request('DataService.addCustomField', $customFieldType, $displayName, $dataType, $headerId); 98 | } 99 | 100 | /** 101 | * @param string $username 102 | * @param string $passwordHash 103 | * @return integer 104 | */ 105 | public function authenticateUser($username, $passwordHash) 106 | { 107 | return $this->client->request('DataService.authenticateUser', $username, $passwordHash); 108 | } 109 | 110 | /** 111 | * @param string $module 112 | * @param string $setting 113 | * @return string 114 | */ 115 | public function getAppSetting($module, $setting) 116 | { 117 | return $this->client->request('DataService.getAppSetting', $module, $setting); 118 | } 119 | 120 | /** 121 | * @param integer $appointmentId 122 | * @return string 123 | */ 124 | public function getAppointmentCal($appointmentId) 125 | { 126 | return $this->client->request('DataService.getAppointmentCal', $appointmentId); 127 | } 128 | 129 | /** 130 | * @param string $username 131 | * @param string $passwordHash 132 | * @return string 133 | */ 134 | public function getTemporaryKey($username, $passwordHash) 135 | { 136 | return $this->client->request('DataService.getTemporaryKey', $username, $passwordHash); 137 | } 138 | 139 | /** 140 | * @param integer $customFieldId 141 | * @param array $values 142 | * @return bool 143 | */ 144 | public function updateCustomField($customFieldId, $values) 145 | { 146 | return $this->client->request('DataService.updateCustomField', $customFieldId, $values); 147 | } 148 | 149 | /** 150 | * @return array 151 | */ 152 | public function getUserInfo() 153 | { 154 | $this->client->needsEmptyKey = false; 155 | 156 | return $this->client->request('DataService.getUserInfo'); 157 | } 158 | 159 | } 160 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/DiscountService.php: -------------------------------------------------------------------------------- 1 | client->request('DiscountService.addFreeTrial', $name, $description, $freeTrialDays, $hidePrice, $subscriptionPlanId); 18 | } 19 | 20 | /** 21 | * @param integer $trialId 22 | * @return array 23 | */ 24 | public function getFreeTrial($trialId) 25 | { 26 | return $this->client->request('DiscountService.getFreeTrial', $trialId); 27 | } 28 | 29 | /** 30 | * @param string $name 31 | * @param string $description 32 | * @param integer $applyDiscountToCommission 33 | * @param integer $percentOrAmt 34 | * @param integer $amt 35 | * @param string $payType 36 | * @return integer 37 | */ 38 | public function addOrderTotalDiscount($name, $description, $applyDiscountToCommission, $percentOrAmt, $amt, $payType) 39 | { 40 | return $this->client->request('DiscountService.addOrderTotalDiscount', $name, $description, $applyDiscountToCommission, $percentOrAmt, $amt, $payType); 41 | } 42 | 43 | /** 44 | * @param integer $id 45 | * @return array 46 | */ 47 | public function getOrderTotalDiscount($id) 48 | { 49 | return $this->client->request('DiscountService.getOrderTotalDiscount', $id); 50 | } 51 | 52 | /** 53 | * @param string $name 54 | * @param string $description 55 | * @param integer $applyDiscountToCommission 56 | * @param integer $amt 57 | * @return integer 58 | */ 59 | public function addCategoryDiscount($name, $description, $applyDiscountToCommission, $amt) 60 | { 61 | return $this->client->request('DiscountService.addCategoryDiscount', $name, $description, $applyDiscountToCommission, $amt); 62 | } 63 | 64 | /** 65 | * @param integer $id 66 | * @return array 67 | */ 68 | public function getCategoryDiscount($id) 69 | { 70 | return $this->client->request('DiscountService.getCategoryDiscount', $id); 71 | } 72 | 73 | /** 74 | * @param integer $id 75 | * @param integer $productId 76 | * @return integer 77 | */ 78 | public function addCategoryAssignmentToCategoryDiscount($id, $productId) 79 | { 80 | return $this->client->request('DiscountService.addCategoryAssignmentToCategoryDiscount', $id, $productId); 81 | } 82 | 83 | /** 84 | * @param integer $id 85 | * @return array 86 | */ 87 | public function getCategoryAssignmentsForCategoryDiscount($id) 88 | { 89 | return $this->client->request('DiscountService.getCategoryAssignmentsForCategoryDiscount', $id); 90 | } 91 | 92 | /** 93 | * @param string $name 94 | * @param string $description 95 | * @param integer $applyDiscountToCommission 96 | * @param integer $productId 97 | * @param integer $percentOrAmt 98 | * @param integer $amt 99 | * @return integer 100 | */ 101 | public function addProductTotalDiscount($name, $description, $applyDiscountToCommission, $productId, $percentOrAmt, $amt) 102 | { 103 | return $this->client->request('DiscountService.addProductTotalDiscount', $name, $description, $applyDiscountToCommission, $productId, $percentOrAmt, $amt); 104 | } 105 | 106 | /** 107 | * @param string $id 108 | * @return array 109 | */ 110 | public function getProductTotalDiscount($id) 111 | { 112 | return $this->client->request('DiscountService.getProductTotalDiscount', $id); 113 | } 114 | 115 | /** 116 | * @param string $name 117 | * @param string $description 118 | * @param integer $applyDiscountToCommission 119 | * @param integer $percentOrAmt 120 | * @param integer $amt 121 | * @return integer 122 | */ 123 | public function addShippingTotalDiscount($name, $description, $applyDiscountToCommission, $percentOrAmt, $amt) 124 | { 125 | return $this->client->request('DiscountService.addShippingTotalDiscount', $name, $description, $applyDiscountToCommission, $percentOrAmt, $amt); 126 | } 127 | 128 | /** 129 | * @param integer $id 130 | * @return array 131 | */ 132 | public function getShippingTotalDiscount($id) 133 | { 134 | return $this->client->request('DiscountService.getShippingTotalDiscount', $id); 135 | } 136 | 137 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/FileService.php: -------------------------------------------------------------------------------- 1 | client->request('FileService.getFile', $fileId); 14 | } 15 | 16 | /** 17 | * @param integer $fileId 18 | * @return mixed 19 | */ 20 | public function getDownloadUrl($fileId) 21 | { 22 | return $this->client->request('FileService.getDownloadUrl', $fileId); 23 | } 24 | 25 | /** 26 | * @param string $fileName 27 | * @param string $base64EncodedData 28 | * @param integer $contactId 29 | * @return mixed 30 | */ 31 | public function uploadFile($contactId, $fileName, $base64EncodedData) 32 | { 33 | return $this->client->request('FileService.uploadFile', $contactId, $fileName, $base64EncodedData); 34 | } 35 | 36 | /** 37 | * @param integer $fileId 38 | * @param string $base64EncodedData 39 | * @return mixed 40 | */ 41 | public function replaceFile($fileId, $base64EncodedData) 42 | { 43 | return $this->client->request('FileService.replaceFile', $fileId, $base64EncodedData); 44 | } 45 | 46 | /** 47 | * @param integer $fileId 48 | * @param string $fileName 49 | * @return mixed 50 | */ 51 | public function renameFile($fileId, $fileName) 52 | { 53 | return $this->client->request('FileService.renameFile', $fileId, $fileName); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/FunnelService.php: -------------------------------------------------------------------------------- 1 | client->request('FunnelService.achieveGoal', $integration, $callName, $contactId); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/InvoiceService.php: -------------------------------------------------------------------------------- 1 | client->request('InvoiceService.createBlankOrder', $contactId, $description, $orderDate, $leadAffiliateId, $saleAffiliateId); 18 | } 19 | 20 | /** 21 | * @param integer $invoiceId 22 | * @param integer $productId 23 | * @param integer $type 24 | * @param float $price 25 | * @param integer $quantity 26 | * @param string $description 27 | * @param string $notes 28 | * @return mixed 29 | */ 30 | public function addOrderItem($invoiceId, $productId, $type, $price, $quantity, $description, $notes) 31 | { 32 | return $this->client->request('InvoiceService.addOrderItem', $invoiceId, $productId, $type, $price, $quantity, $description, $notes); 33 | } 34 | 35 | /** 36 | * @param integer $invoiceId 37 | * @param string $notes 38 | * @param integer $creditCardId 39 | * @param integer $merchantAccountId 40 | * @param boolean $bypassCommissions 41 | * @return mixed 42 | */ 43 | public function chargeInvoice($invoiceId, $notes, $creditCardId, $merchantAccountId, $bypassCommissions) 44 | { 45 | return $this->client->request('InvoiceService.chargeInvoice', $invoiceId, $notes, $creditCardId, $merchantAccountId, $bypassCommissions); 46 | } 47 | 48 | /** 49 | * @param integer $recurringOrderId 50 | * @return mixed 51 | */ 52 | public function deleteSubscription($recurringOrderId) 53 | { 54 | return $this->client->request('InvoiceService.deleteSubscription', $recurringOrderId); 55 | } 56 | 57 | /** 58 | * @param integer $invoiceId 59 | * @return mixed 60 | */ 61 | public function deleteInvoice($invoiceId) 62 | { 63 | return $this->client->request('InvoiceService.deleteInvoice', $invoiceId); 64 | } 65 | 66 | /** 67 | * @param integer $contactId 68 | * @param boolean $allowDuplicate 69 | * @param integer $cProgramId 70 | * @param integer $qty 71 | * @param float $price 72 | * @param boolean $taxable 73 | * @param integer $merchantAccountId 74 | * @param integer $creditCardId 75 | * @param integer $affiliated 76 | * @param integer $daysTillCharge 77 | * @return mixed 78 | */ 79 | public function addRecurringOrder($contactId, $allowDuplicate, $cProgramId, $qty, $price, $taxable, $merchantAccountId, $creditCardId, $affiliated, $daysTillCharge) 80 | { 81 | return $this->client->request('InvoiceService.addRecurringOrder', $contactId, $allowDuplicate, $cProgramId, $qty, $price, $taxable, $merchantAccountId, $creditCardId, $affiliated, $daysTillCharge); 82 | } 83 | 84 | /** 85 | * @param integer $recurringOrderId 86 | * @param integer $affiliateId 87 | * @param float $amount 88 | * @param integer $payoutType 89 | * @param string $description 90 | * @return mixed 91 | */ 92 | public function addRecurringCommissionOverride($recurringOrderId, $affiliateId, $amount, $payoutType, $description) 93 | { 94 | return $this->client->request('InvoiceService.addRecurringCommissionOverride', $recurringOrderId, $affiliateId, $amount, $payoutType, $description); 95 | } 96 | 97 | /** 98 | * @param integer $recurringOrderId 99 | * @return mixed 100 | */ 101 | public function createInvoiceForRecurring($recurringOrderId) 102 | { 103 | return $this->client->request('InvoiceService.createInvoiceForRecurring', $recurringOrderId); 104 | } 105 | 106 | /** 107 | * @param integer $invoiceId 108 | * @param float $amt 109 | * @param string $paymentDate 110 | * @param string $paymentType 111 | * @param string $paymentDescription 112 | * @param boolean $bypassCommissions 113 | * @return mixed 114 | */ 115 | public function addManualPayment($invoiceId, $amt, $paymentDate, $paymentType, $paymentDescription, $bypassCommissions) 116 | { 117 | return $this->client->request('InvoiceService.addManualPayment', $invoiceId, $amt, $paymentDate, $paymentType, $paymentDescription, $bypassCommissions); 118 | } 119 | 120 | /** 121 | * @param integer $invoiceId 122 | * @param boolean $autoCharge 123 | * @param integer $creditCardId 124 | * @param integer $merchantAccountId 125 | * @param integer $daysBetweenRetry 126 | * @param integer $maxRetry 127 | * @param float $initialPmtAmt 128 | * @param string $initialPmtDate 129 | * @param string $plantStartDate 130 | * @param integer $numPayments 131 | * @param integer $daysBetweenPayments 132 | * @return mixed 133 | */ 134 | public function addPaymentPlan($invoiceId, $autoCharge, $creditCardId, $merchantAccountId, $daysBetweenRetry, $maxRetry, $initialPmtAmt, $initialPmtDate, $plantStartDate, $numPayments, $daysBetweenPayments) 135 | { 136 | return $this->client->request('InvoiceService.addPaymentPlan', $invoiceId, $autoCharge, $creditCardId, $merchantAccountId, $daysBetweenRetry, $maxRetry, $initialPmtAmt, $initialPmtDate, $plantStartDate, $numPayments, $daysBetweenPayments); 137 | } 138 | 139 | /** 140 | * @param integer $invoiceId 141 | * @return mixed 142 | */ 143 | public function calculateAmountOwed($invoiceId) 144 | { 145 | return $this->client->request('InvoiceService.calculateAmountOwed', $invoiceId); 146 | } 147 | 148 | /** 149 | * @return mixed 150 | */ 151 | public function getAllPaymentOptions() 152 | { 153 | return $this->client->request('InvoiceService.getAllPaymentOptions'); 154 | } 155 | 156 | /** 157 | * @param integer $invoiceId 158 | * @return mixed 159 | */ 160 | public function getPayments($invoiceId) 161 | { 162 | return $this->client->request('InvoiceService.getPayments', $invoiceId); 163 | } 164 | 165 | /** 166 | * @param integer $contactId 167 | * @param string $last4 168 | * @return mixed 169 | */ 170 | public function locateExistingCard($contactId, $last4) 171 | { 172 | return $this->client->request('InvoiceService.locateExistingCard', $contactId, $last4); 173 | } 174 | 175 | /** 176 | * @param integer $invoiceId 177 | * @return mixed 178 | */ 179 | public function recalculateTax($invoiceId) 180 | { 181 | return $this->client->request('InvoiceService.recalculateTax', $invoiceId); 182 | } 183 | 184 | /** 185 | * @param string $cardType 186 | * @param integer $contactId 187 | * @param string $cardNumber 188 | * @param string $expirationMonth 189 | * @param string $expirationYear 190 | * @param string $cvv2 191 | * @return array 192 | */ 193 | public function validateCreditCard($cardType, $contactId, $cardNumber, $expirationMonth, $expirationYear, $cvv2) 194 | { 195 | $data = array( 196 | 'CardType' => $cardType, 197 | 'ContactId' => $contactId, 198 | 'CardNumber' => $cardNumber, 199 | 'ExpirationMonth' => $expirationMonth, 200 | 'ExpirationYear' => $expirationYear, 201 | 'CVV2' => $cvv2 202 | ); 203 | 204 | return $this->client->request('InvoiceService.validateCreditCard', $data); 205 | } 206 | 207 | /** 208 | * @return mixed 209 | */ 210 | public function getAllShippingOptions() 211 | { 212 | return $this->client->request('InvoiceService.getAllShippingOptions'); 213 | } 214 | 215 | /** 216 | * @param integer $recurringOrderId 217 | * @param string $nextBillDate 218 | * @return mixed 219 | */ 220 | public function updateJobRecurringNextBillDate($recurringOrderId, $nextBillDate) 221 | { 222 | return $this->client->request('InvoiceService.updateJobRecurringNextBillDate', $recurringOrderId, $nextBillDate); 223 | } 224 | 225 | /** 226 | * @param integer $invoiceId 227 | * @param integer $affiliateId 228 | * @param integer $productId 229 | * @param integer $percentage 230 | * @param float $amount 231 | * @param integer $payoutType 232 | * @param string $description 233 | * @param string $date 234 | * @return mixed 235 | */ 236 | public function addOrderCommissionOverride($invoiceId, $affiliateId, $productId, $percentage, $amount, $payoutType, $description, $date) 237 | { 238 | return $this->client->request('InvoiceService.addOrderCommissionOverride', $invoiceId, $affiliateId, $productId, $percentage, $amount, $payoutType, $description, $date); 239 | } 240 | 241 | } 242 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/OrderService.php: -------------------------------------------------------------------------------- 1 | client->request('OrderService.placeOrder', $contactId, $creditCardId, $payPlanId, $productIds, $subscriptionPlanIds, $processSpecials, $promoCodes, $leadAffiliateId, $affiliateId); 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/ProductService.php: -------------------------------------------------------------------------------- 1 | client->request('ProductService.getInventory', $productId); 14 | } 15 | 16 | /** 17 | * @param integer $productId 18 | * @return mixed 19 | */ 20 | public function incrementInventory($productId) 21 | { 22 | return $this->client->request('ProductService.incrementInventory', $productId); 23 | } 24 | 25 | /** 26 | * @param integer $productId 27 | * @return mixed 28 | */ 29 | public function decrementInventory($productId) 30 | { 31 | return $this->client->request('ProductService.decrementInventory', $productId); 32 | } 33 | 34 | /** 35 | * @param integer $productId 36 | * @param integer $quantity 37 | * @return mixed 38 | */ 39 | public function increaseInventory($productId, $quantity) 40 | { 41 | return $this->client->request('ProductService.increaseInventory', $productId, $quantity); 42 | } 43 | 44 | /** 45 | * @param integer $productId 46 | * @param integer $quantity 47 | * @return mixed 48 | */ 49 | public function decreaseInventory($productId, $quantity) 50 | { 51 | return $this->client->request('ProductService.decreaseInventory', $productId, $quantity); 52 | } 53 | 54 | /** 55 | * @param integer $creditCardId 56 | * @return mixed 57 | */ 58 | public function deactivateCreditCard($creditCardId) 59 | { 60 | return $this->client->request('ProductService.deactivateCreditCard', $creditCardId); 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/AppointmentService.php: -------------------------------------------------------------------------------- 1 | full_url.'/search'; 11 | 12 | return $url; 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/CampaignService.php: -------------------------------------------------------------------------------- 1 | client->restfulRequest('get', $this->getFullUrl($this->id . '/tags')); 26 | $this->fill($data); 27 | 28 | return $this; 29 | } 30 | 31 | public function emails() 32 | { 33 | $data = $this->client->restfulRequest('get', $this->getFullUrl($this->id . '/emails')); 34 | $this->fill($data); 35 | 36 | return $this; 37 | } 38 | 39 | public function addTags($tagIds) 40 | { 41 | if ( ! is_array($tagIds)) { 42 | throw new InfusionsoftException('Must be an array of tag ids'); 43 | } elseif (count($tagIds) > 100) { 44 | throw new InfusionsoftException('A maximum of 100 tag ids can be added at once'); 45 | } 46 | 47 | $tags = []; 48 | $tags['tagIds'] = $tagIds; 49 | 50 | $response = $this->client->restfulRequest('post', $this->getFullUrl($this->id . '/tags'), $tags); 51 | 52 | return $response; 53 | 54 | } 55 | 56 | public function create(array $attributes = [], $dupCheck = false) 57 | { 58 | $this->mock($attributes); 59 | if ($dupCheck) { 60 | $data = $this->client->restfulRequest('put', $this->getFullUrl($this->id), (array)$this->toArray()); 61 | $this->fill($data); 62 | } else { 63 | $this->save(); 64 | } 65 | 66 | return $this; 67 | } 68 | 69 | public function removeTags($tagIds) 70 | { 71 | if ( ! is_array($tagIds)) { 72 | throw new InfusionsoftException('Must be an array of tag ids'); 73 | } elseif (count($tagIds) > 100) { 74 | throw new InfusionsoftException('A maximum of 100 tag ids can be deleted at once'); 75 | } 76 | 77 | $tagIds = ['ids' => implode(",", $tagIds)]; 78 | 79 | $response = $this->client->restfulRequest('delete', $this->getFullUrl($this->id . '/tags'), $tagIds); 80 | 81 | return $response; 82 | 83 | } 84 | 85 | public function creditCards() 86 | { 87 | $data = $this->client->restfulRequest('get', $this->getFullUrl($this->id . '/creditCards')); 88 | $this->fill($data); 89 | 90 | return $this; 91 | } 92 | 93 | public function addCreditCard($cardDetails) 94 | { 95 | if (!is_array($cardDetails)) { 96 | throw new InfusionsoftException('Must be an array of card details'); 97 | } 98 | 99 | $response = $this->client->restfulRequest('post', $this->getFullUrl($this->id . '/creditCards'), $cardDetails); 100 | 101 | return $response; 102 | } 103 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/CustomFieldService.php: -------------------------------------------------------------------------------- 1 | client->restfulRequest('post', $this->getFullUrl('/queue'), $attributes); 18 | return $response; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/FileService.php: -------------------------------------------------------------------------------- 1 | attributes['id'])) { 15 | return $this->attributes['id']; 16 | } 17 | if(isset($this->attributes['file_descriptor'])) { 18 | return $this->attributes['file_descriptor']['id']; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/MerchantService.php: -------------------------------------------------------------------------------- 1 | client->restfulRequest('get', 'https://api.infusionsoft.com/crm/rest/v1/opportunity/stage_pipeline'); 17 | $this->fill($data); 18 | 19 | return $this; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/OrderService.php: -------------------------------------------------------------------------------- 1 | client->restfulRequest('post', $this->getFullUrl($this->id . '/payments'), $paymentDetails); 15 | 16 | return $response; 17 | } 18 | 19 | public function deleteOrderItem($id = null) 20 | { 21 | 22 | if(!$id) return false; 23 | 24 | $response = $this->client->restfulRequest('delete', $this->getFullUrl($this->id . '/items/'. $id)); 25 | 26 | return $response; 27 | 28 | } 29 | public function transactions() 30 | { 31 | 32 | $response = $this->client->restfulRequest('get', $this->getFullUrl($this->id . '/transactions')); 33 | 34 | return $response; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/ProductService.php: -------------------------------------------------------------------------------- 1 | full_url.'/search'; 13 | 14 | return $url; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/RestModel.php: -------------------------------------------------------------------------------- 1 | client = $client; 96 | 97 | $this->bootIfNotBooted(); 98 | } 99 | 100 | /** 101 | * Returns the full URL for the query, optionally concatinated with additional URI elements 102 | * 103 | * @return string 104 | */ 105 | public function getFullUrl($additional = null) 106 | { 107 | $url = $this->full_url; 108 | if (substr($url, -1) != '/') { 109 | $url .= '/'; 110 | } 111 | 112 | if ($additional) { 113 | $additional = ltrim($additional, '/'); 114 | } 115 | 116 | return $url . $additional; 117 | } 118 | 119 | /** 120 | * Returns the full URL for the index request, allowing for specific index endpoints 121 | * 122 | * @return string 123 | */ 124 | public function getIndexUrl() 125 | { 126 | $url = $this->full_url; 127 | 128 | return $url; 129 | } 130 | 131 | /** 132 | * Mock this model from itself. 133 | * 134 | * @param array $attributes 135 | * 136 | * @return self 137 | */ 138 | public function mock(array $attributes = []) 139 | { 140 | $this->fill($attributes); 141 | 142 | return $this; 143 | } 144 | 145 | /** 146 | * Creates a new object and saves it in storage/API. 147 | * 148 | * @param array $attributes 149 | * 150 | * @return self 151 | */ 152 | public function create(array $attributes = []) 153 | { 154 | $this->mock($attributes); 155 | $this->save(); 156 | 157 | return $this; 158 | } 159 | 160 | /** 161 | * Save this model to storage/api. 162 | * 163 | * @return self 164 | */ 165 | public function save() 166 | { 167 | // well, is it a post or a put? we need to figure out if this thing exists or not 168 | // long story short, if the "id" is set, it's an update. 169 | if (isset($this->{$this->primaryKey})) { 170 | $data = $this->client->restfulRequest(strtolower($this->updateVerb), 171 | $this->getFullUrl($this->{$this->primaryKey}), 172 | (array)$this->toArray()); 173 | } else { 174 | $data = $this->client->restfulRequest('post', $this->getFullUrl(), (array)$this->toArray()); 175 | } 176 | 177 | $this->fill($data); 178 | 179 | return $this; 180 | } 181 | 182 | public function with($optional) 183 | { 184 | if (!is_array($optional) && is_string($optional)) { 185 | $this->optionalProperities[] = $optional; 186 | } else { 187 | $this->optionalProperities = $optional; 188 | } 189 | 190 | return $this; 191 | } 192 | 193 | public function find($id) 194 | { 195 | 196 | if (!empty($this->optionalProperities)) { 197 | $data = $this->client->restfulRequest('get', 198 | $this->getFullUrl($id), ['optional_properties' => implode(",", $this->optionalProperities)]); 199 | } else { 200 | $data = $this->client->restfulRequest('get', $this->getFullUrl($id)); 201 | } 202 | 203 | $this->fill($data); 204 | 205 | return $this; 206 | } 207 | 208 | public function sync($syncToken) 209 | { 210 | $this->where['sync_token'] = $syncToken; 211 | $data = $this->client->restfulRequest('get', $this->getFullUrl()); 212 | $this->fill($data); 213 | 214 | return $this; 215 | } 216 | 217 | public function where($key, $value = null) 218 | { 219 | if (is_array($key)) { 220 | foreach ($key as $k => $v) { 221 | $this->where[$k] = $v; 222 | } 223 | 224 | return $this; 225 | } 226 | 227 | $this->where[$key] = $value; 228 | 229 | return $this; 230 | } 231 | 232 | public function delete() 233 | { 234 | $response = $this->client->restfulRequest('delete', 235 | $this->getFullUrl($this->{$this->primaryKey})); 236 | 237 | return true; 238 | } 239 | 240 | public function get() 241 | { 242 | 243 | $params = $this->where; 244 | if (!empty($this->optionalProperities)) { 245 | $params['optional_properties'] = implode(',', $this->optionalProperities); 246 | } 247 | 248 | if (!empty($this->where)) { 249 | $data = $this->client->restfulRequest('get', $this->getIndexUrl(), $params); 250 | } else { 251 | $data = $this->client->restfulRequest('get', $this->getIndexUrl()); 252 | } 253 | 254 | $cursor = []; 255 | 256 | if (isset($data['sync_token'])) { 257 | $cursor = $data['sync_token']; 258 | } 259 | 260 | $collection = $this->collect($data, $cursor); 261 | 262 | return $collection; 263 | } 264 | 265 | public function first() 266 | { 267 | 268 | $this->where('limit', 1); 269 | 270 | $params = $this->where; 271 | if (!empty($this->optionalProperities)) { 272 | $params['optional_properties'] = implode(',', $this->optionalProperities); 273 | } 274 | 275 | if (!empty($params)) { 276 | $data = $this->client->restfulRequest('get', $this->getIndexUrl(), $params); 277 | } else { 278 | $data = $this->client->restfulRequest('get', $this->getIndexUrl()); 279 | } 280 | 281 | $cursor = []; 282 | 283 | if (isset($data['sync_token'])) { 284 | $cursor = $data['sync_token']; 285 | } 286 | 287 | if ($data['count'] === 0) { 288 | throw new InfusionsoftException('No Results Found'); 289 | } 290 | 291 | $collection = $this->collect($data, $cursor); 292 | 293 | return $collection[0]; 294 | 295 | } 296 | 297 | public function count() 298 | { 299 | $this->where('limit', 1); 300 | 301 | $data = $this->client->restfulRequest('get', $this->getIndexUrl(), $this->where); 302 | 303 | return $data['count']; 304 | } 305 | 306 | public function all() 307 | { 308 | $data = $this->client->restfulRequest('get', $this->getIndexUrl()); 309 | 310 | $cursor = []; 311 | 312 | if (isset($data['sync_token'])) { 313 | $cursor = $data['sync_token']; 314 | } 315 | 316 | $collection = $this->collect($data, $cursor); 317 | 318 | return $collection; 319 | } 320 | 321 | public function model() 322 | { 323 | $data = $this->client->restfulRequest('get', $this->getFullUrl('model')); 324 | $this->fill($data); 325 | 326 | return $this; 327 | } 328 | 329 | 330 | public function collect(array $array, $cursor = []) 331 | { 332 | $items = []; 333 | 334 | $base_object = $array; 335 | 336 | if (!empty($this->return_key)) { 337 | $base_object = $array[$this->return_key]; 338 | } 339 | 340 | foreach ($base_object as $item) { 341 | $thing = clone $this; 342 | array_push($items, $thing->mock($item)); 343 | } 344 | 345 | return new InfusionsoftCollection($items); 346 | } 347 | 348 | /** 349 | * Check if the model needs to be booted and if so, do it. 350 | * 351 | * @return void 352 | */ 353 | protected function bootIfNotBooted() 354 | { 355 | $class = get_class($this); 356 | 357 | if (!isset(static::$booted[$class])) { 358 | static::$booted[$class] = true; 359 | 360 | static::boot(); 361 | } 362 | } 363 | 364 | /** 365 | * The "booting" method of the model. 366 | * 367 | * @return void 368 | */ 369 | protected static function boot() 370 | { 371 | if (function_exists('class_uses_recursive')) { 372 | static::bootTraits(); 373 | } 374 | } 375 | 376 | /** 377 | * Boot all of the bootable traits on the model. 378 | * 379 | * @return void 380 | */ 381 | protected static function bootTraits() 382 | { 383 | foreach (class_uses_recursive(get_called_class()) as $trait) { 384 | if (method_exists(get_called_class(), $method = 'boot' . class_basename($trait))) { 385 | forward_static_call([get_called_class(), $method]); 386 | } 387 | } 388 | } 389 | 390 | /** 391 | * Fill the model with an array of attributes. 392 | * 393 | * @param array $attributes 394 | * 395 | * @return self 396 | */ 397 | public function fill(array $attributes) 398 | { 399 | foreach ($attributes as $key => $value) { 400 | $this->setAttribute($key, $value); 401 | } 402 | 403 | return $this; 404 | } 405 | 406 | /** 407 | * Create a new instance of the given model. 408 | * 409 | * @param array $attributes 410 | * @param bool $exists 411 | * 412 | * @return self 413 | */ 414 | public function newInstance($attributes = array()) 415 | { 416 | $model = new static((array)$attributes); 417 | 418 | return $model; 419 | } 420 | 421 | /** 422 | * Create a collection of models from plain arrays. 423 | * 424 | * @param array $items 425 | * 426 | * @return array 427 | */ 428 | public static function hydrate(array $items) 429 | { 430 | $instance = new static; 431 | 432 | $items = array_map(function ($item) use ($instance) { 433 | return $instance->newInstance($item); 434 | }, $items); 435 | 436 | return $items; 437 | } 438 | 439 | /** 440 | * Sets the HTTP verb used to update the service 441 | * 442 | * @return string 443 | */ 444 | public function setUpdateVerb($verb = 'put') 445 | { 446 | $this->updateVerb = $verb; 447 | 448 | return $this->updateVerb; 449 | } 450 | 451 | /** 452 | * Sets the primary key on the object 453 | * 454 | * @return string 455 | */ 456 | public function setPrimaryKey($key = 'id') 457 | { 458 | $this->primaryKey = $key; 459 | 460 | return $this->primaryKey; 461 | } 462 | 463 | /** 464 | * Retrieves the HTTP verb used to updated the service 465 | * 466 | * @return string 467 | */ 468 | public function getUpdateVerb() 469 | { 470 | return $this->updateVerb; 471 | } 472 | 473 | /** 474 | * Get the hidden attributes for the model. 475 | * 476 | * @return array 477 | */ 478 | public function getHidden() 479 | { 480 | return $this->hidden; 481 | } 482 | 483 | /** 484 | * Set the hidden attributes for the model. 485 | * 486 | * @param array $hidden 487 | * 488 | * @return void 489 | */ 490 | public function setHidden(array $hidden) 491 | { 492 | $this->hidden = $hidden; 493 | } 494 | 495 | /** 496 | * Add hidden attributes for the model. 497 | * 498 | * @param array|string|null $attributes 499 | * 500 | * @return void 501 | */ 502 | public function addHidden($attributes = null) 503 | { 504 | $attributes = is_array($attributes) ? $attributes : func_get_args(); 505 | 506 | $this->hidden = array_merge($this->hidden, $attributes); 507 | } 508 | 509 | /** 510 | * Get the visible attributes for the model. 511 | * 512 | * @return array 513 | */ 514 | public function getVisible() 515 | { 516 | return $this->visible; 517 | } 518 | 519 | /** 520 | * Set the visible attributes for the model. 521 | * 522 | * @param array $visible 523 | * 524 | * @return void 525 | */ 526 | public function setVisible(array $visible) 527 | { 528 | $this->visible = $visible; 529 | } 530 | 531 | /** 532 | * Add visible attributes for the model. 533 | * 534 | * @param array|string|null $attributes 535 | * 536 | * @return void 537 | */ 538 | public function addVisible($attributes = null) 539 | { 540 | $attributes = is_array($attributes) ? $attributes : func_get_args(); 541 | 542 | $this->visible = array_merge($this->visible, $attributes); 543 | } 544 | 545 | /** 546 | * Set the accessors to append to model arrays. 547 | * 548 | * @param array $appends 549 | * 550 | * @return void 551 | */ 552 | public function setAppends(array $appends) 553 | { 554 | $this->appends = $appends; 555 | } 556 | 557 | /** 558 | * Convert the model instance to JSON. 559 | * 560 | * @param int $options 561 | * 562 | * @return string 563 | */ 564 | public function toJson($options = 0) 565 | { 566 | return json_encode($this->toArray(), $options); 567 | } 568 | 569 | /** 570 | * Convert the object into something JSON serializable. 571 | * 572 | * @return array 573 | */ 574 | public function jsonSerialize() 575 | { 576 | return $this->toArray(); 577 | } 578 | 579 | /** 580 | * Convert the model instance to an array. 581 | * 582 | * @return array 583 | */ 584 | public function toArray() 585 | { 586 | return $this->attributesToArray(); 587 | } 588 | 589 | /** 590 | * Convert the model's attributes to an array. 591 | * 592 | * @return array 593 | */ 594 | public function attributesToArray() 595 | { 596 | $attributes = $this->getArrayableAttributes(); 597 | 598 | $mutatedAttributes = $this->getMutatedAttributes(); 599 | 600 | // We want to spin through all the mutated attributes for this model and call 601 | // the mutator for the attribute. We cache off every mutated attributes so 602 | // we don't have to constantly check on attributes that actually change. 603 | foreach ($mutatedAttributes as $key) { 604 | if (!array_key_exists($key, $attributes)) { 605 | continue; 606 | } 607 | 608 | $attributes[$key] = $this->mutateAttributeForArray($key, $attributes[$key]); 609 | } 610 | 611 | // Next we will handle any casts that have been setup for this model and cast 612 | // the values to their appropriate type. If the attribute has a mutator we 613 | // will not perform the cast on those attributes to avoid any confusion. 614 | foreach ($this->casts as $key => $value) { 615 | if (!array_key_exists($key, $attributes) || in_array($key, $mutatedAttributes)) { 616 | continue; 617 | } 618 | 619 | $attributes[$key] = $this->castAttribute($key, $attributes[$key]); 620 | } 621 | 622 | // Here we will grab all of the appended, calculated attributes to this model 623 | // as these attributes are not really in the attributes array, but are run 624 | // when we need to array or JSON the model for convenience to the coder. 625 | foreach ($this->getArrayableAppends() as $key) { 626 | $attributes[$key] = $this->mutateAttributeForArray($key, null); 627 | } 628 | 629 | return $attributes; 630 | } 631 | 632 | /** 633 | * Get an attribute array of all arrayable attributes. 634 | * 635 | * @return array 636 | */ 637 | protected function getArrayableAttributes() 638 | { 639 | return $this->getArrayableItems($this->attributes); 640 | } 641 | 642 | /** 643 | * Get all of the appendable values that are arrayable. 644 | * 645 | * @return array 646 | */ 647 | protected function getArrayableAppends() 648 | { 649 | if (!count($this->appends)) { 650 | return []; 651 | } 652 | 653 | return $this->getArrayableItems(array_combine($this->appends, $this->appends)); 654 | } 655 | 656 | /** 657 | * Get an attribute array of all arrayable values. 658 | * 659 | * @param array $values 660 | * 661 | * @return array 662 | */ 663 | protected function getArrayableItems(array $values) 664 | { 665 | if (count($this->visible) > 0) { 666 | return array_intersect_key($values, array_flip($this->visible)); 667 | } 668 | 669 | return array_diff_key($values, array_flip($this->hidden)); 670 | } 671 | 672 | /** 673 | * Get an attribute from the model. 674 | * 675 | * @param string $key 676 | * 677 | * @return mixed 678 | */ 679 | public function getAttribute($key) 680 | { 681 | $inAttributes = array_key_exists($key, $this->attributes); 682 | 683 | // If the key references an attribute, we can just go ahead and return the 684 | // plain attribute value from the model. This allows every attribute to 685 | // be dynamically accessed through the _get method without accessors. 686 | if ($inAttributes or $this->hasGetMutator($key)) { 687 | return $this->getAttributeValue($key); 688 | } 689 | } 690 | 691 | /** 692 | * Get a plain attribute (not a relationship). 693 | * 694 | * @param string $key 695 | * 696 | * @return mixed 697 | */ 698 | protected function getAttributeValue($key) 699 | { 700 | $value = $this->getAttributeFromArray($key); 701 | 702 | // If the attribute has a get mutator, we will call that then return what 703 | // it returns as the value, which is useful for transforming values on 704 | // retrieval from the model to a form that is more useful for usage. 705 | if ($this->hasGetMutator($key)) { 706 | return $this->mutateAttribute($key, $value); 707 | } 708 | 709 | // If the attribute exists within the cast array, we will convert it to 710 | // an appropriate native PHP type dependant upon the associated value 711 | // given with the key in the pair. Dayle made this comment line up. 712 | if ($this->hasCast($key)) { 713 | $value = $this->castAttribute($key, $value); 714 | } 715 | 716 | return $value; 717 | } 718 | 719 | /** 720 | * Get an attribute from the $attributes array. 721 | * 722 | * @param string $key 723 | * 724 | * @return mixed 725 | */ 726 | protected function getAttributeFromArray($key) 727 | { 728 | if (array_key_exists($key, $this->attributes)) { 729 | return $this->attributes[$key]; 730 | } 731 | } 732 | 733 | /** 734 | * Determine if a get mutator exists for an attribute. 735 | * 736 | * @param string $key 737 | * 738 | * @return bool 739 | */ 740 | public function hasGetMutator($key) 741 | { 742 | return method_exists($this, 'get' . $this->studly($key) . 'Attribute'); 743 | } 744 | 745 | /** 746 | * Get the value of an attribute using its mutator. 747 | * 748 | * @param string $key 749 | * @param mixed $value 750 | * 751 | * @return mixed 752 | */ 753 | protected function mutateAttribute($key, $value) 754 | { 755 | return $this->{'get' . $this->studly($key) . 'Attribute'}($value); 756 | } 757 | 758 | /** 759 | * Get the value of an attribute using its mutator for array conversion. 760 | * 761 | * @param string $key 762 | * @param mixed $value 763 | * 764 | * @return mixed 765 | */ 766 | protected function mutateAttributeForArray($key, $value) 767 | { 768 | $value = $this->mutateAttribute($key, $value); 769 | 770 | return $value instanceof ArrayableInterface ? $value->toArray() : $value; 771 | } 772 | 773 | /** 774 | * Determine whether an attribute should be casted to a native type. 775 | * 776 | * @param string $key 777 | * 778 | * @return bool 779 | */ 780 | protected function hasCast($key) 781 | { 782 | return array_key_exists($key, $this->casts); 783 | } 784 | 785 | /** 786 | * Determine whether a value is JSON castable for inbound manipulation. 787 | * 788 | * @param string $key 789 | * 790 | * @return bool 791 | */ 792 | protected function isJsonCastable($key) 793 | { 794 | if ($this->hasCast($key)) { 795 | return in_array($this->getCastType($key), ['array', 'json', 'object'], true); 796 | } 797 | 798 | return false; 799 | } 800 | 801 | /** 802 | * Get the type of cast for a model attribute. 803 | * 804 | * @param string $key 805 | * 806 | * @return string 807 | */ 808 | protected function getCastType($key) 809 | { 810 | return trim(strtolower($this->casts[$key])); 811 | } 812 | 813 | /** 814 | * Cast an attribute to a native PHP type. 815 | * 816 | * @param string $key 817 | * @param mixed $value 818 | * 819 | * @return mixed 820 | */ 821 | protected function castAttribute($key, $value) 822 | { 823 | if (is_null($value)) { 824 | return $value; 825 | } 826 | 827 | switch ($this->getCastType($key)) { 828 | case 'int': 829 | case 'integer': 830 | return (int)$value; 831 | case 'real': 832 | case 'float': 833 | case 'double': 834 | return (float)$value; 835 | case 'string': 836 | return (string)$value; 837 | case 'bool': 838 | case 'boolean': 839 | return (bool)$value; 840 | case 'object': 841 | return json_decode($value); 842 | case 'array': 843 | case 'json': 844 | return json_decode($value, true); 845 | default: 846 | return $value; 847 | } 848 | } 849 | 850 | /** 851 | * Set a given attribute on the model. 852 | * 853 | * @param string $key 854 | * @param mixed $value 855 | * 856 | * @return void 857 | */ 858 | public function setAttribute($key, $value) 859 | { 860 | // First we will check for the presence of a mutator for the set operation 861 | // which simply lets the developers tweak the attribute as it is set on 862 | // the model, such as "json_encoding" an listing of data for storage. 863 | if ($this->hasSetMutator($key)) { 864 | $method = 'set' . $this->studly($key) . 'Attribute'; 865 | 866 | return $this->{$method}($value); 867 | } 868 | 869 | if ($this->isJsonCastable($key)) { 870 | $value = json_encode($value); 871 | } 872 | 873 | $this->attributes[$key] = $value; 874 | } 875 | 876 | /** 877 | * Determine if a set mutator exists for an attribute. 878 | * 879 | * @param string $key 880 | * 881 | * @return bool 882 | */ 883 | public function hasSetMutator($key) 884 | { 885 | return method_exists($this, 'set' . $this->studly($key) . 'Attribute'); 886 | } 887 | 888 | /** 889 | * Clone the model into a new, non-existing instance. 890 | * 891 | * @return self 892 | */ 893 | public function replicate() 894 | { 895 | with($instance = new static)->fill($this->attributes); 896 | 897 | return $instance; 898 | } 899 | 900 | /** 901 | * Get all of the current attributes on the model. 902 | * 903 | * @return array 904 | */ 905 | public function getAttributes() 906 | { 907 | return $this->attributes; 908 | } 909 | 910 | /** 911 | * Get the mutated attributes for a given instance. 912 | * 913 | * @return array 914 | */ 915 | public function getMutatedAttributes() 916 | { 917 | $class = get_class($this); 918 | 919 | if (!isset(static::$mutatorCache[$class])) { 920 | static::cacheMutatedAttributes($class); 921 | } 922 | 923 | return static::$mutatorCache[$class]; 924 | } 925 | 926 | /** 927 | * Extract and cache all the mutated attributes of a class. 928 | * 929 | * @param string $class 930 | * 931 | * @return void 932 | */ 933 | public static function cacheMutatedAttributes($class) 934 | { 935 | $mutatedAttributes = array(); 936 | 937 | // Here we will extract all of the mutated attributes so that we can quickly 938 | // spin through them after we export models to their array form, which we 939 | // need to be fast. This'll let us know the attributes that can mutate. 940 | foreach (get_class_methods($class) as $method) { 941 | if (strpos($method, 'Attribute') !== false && preg_match('/^get(.+)Attribute$/', $method, $matches)) { 942 | if (static::$snakeAttributes) { 943 | $matches[1] = snake_case($matches[1]); 944 | } 945 | 946 | $mutatedAttributes[] = lcfirst($matches[1]); 947 | } 948 | } 949 | 950 | static::$mutatorCache[$class] = $mutatedAttributes; 951 | } 952 | 953 | /** 954 | * Dynamically retrieve attributes on the model. 955 | * 956 | * @param string $key 957 | * 958 | * @return mixed 959 | */ 960 | public function __get($key) 961 | { 962 | return $this->getAttribute($key); 963 | } 964 | 965 | /** 966 | * Dynamically set attributes on the model. 967 | * 968 | * @param string $key 969 | * @param mixed $value 970 | * 971 | * @return void 972 | */ 973 | public function __set($key, $value) 974 | { 975 | $this->setAttribute($key, $value); 976 | } 977 | 978 | /** 979 | * Determine if the given attribute exists. 980 | * 981 | * @param mixed $offset 982 | * 983 | * @return bool 984 | */ 985 | public function offsetExists($offset) 986 | { 987 | return isset($this->$offset); 988 | } 989 | 990 | /** 991 | * Get the value for a given offset. 992 | * 993 | * @param mixed $offset 994 | * 995 | * @return mixed 996 | */ 997 | public function offsetGet($offset) 998 | { 999 | return $this->$offset; 1000 | } 1001 | 1002 | /** 1003 | * Set the value for a given offset. 1004 | * 1005 | * @param mixed $offset 1006 | * @param mixed $value 1007 | * 1008 | * @return void 1009 | */ 1010 | public function offsetSet($offset, $value) 1011 | { 1012 | $this->$offset = $value; 1013 | } 1014 | 1015 | /** 1016 | * Unset the value for a given offset. 1017 | * 1018 | * @param mixed $offset 1019 | * 1020 | * @return void 1021 | */ 1022 | public function offsetUnset($offset) 1023 | { 1024 | unset($this->$offset); 1025 | } 1026 | 1027 | /** 1028 | * Determine if an attribute exists on the model. 1029 | * 1030 | * @param string $key 1031 | * 1032 | * @return void 1033 | */ 1034 | public function __isset($key) 1035 | { 1036 | return ((isset($this->attributes[$key]) || isset($this->relations[$key])) || ($this->hasGetMutator($key) && !is_null($this->getAttributeValue($key)))); 1037 | } 1038 | 1039 | /** 1040 | * Unset an attribute on the model. 1041 | * 1042 | * @param string $key 1043 | * 1044 | * @return void 1045 | */ 1046 | public function __unset($key) 1047 | { 1048 | unset($this->attributes[$key]); 1049 | } 1050 | 1051 | /** 1052 | * Handle dynamic static method calls into the method. 1053 | * 1054 | * @param string $method 1055 | * @param array $parameters 1056 | * 1057 | * @return mixed 1058 | */ 1059 | public static function __callStatic($method, $parameters) 1060 | { 1061 | $instance = new static; 1062 | 1063 | return call_user_func_array(array($instance, $method), $parameters); 1064 | } 1065 | 1066 | /** 1067 | * Convert the model to its string representation. 1068 | * 1069 | * @return string 1070 | */ 1071 | public function __toString() 1072 | { 1073 | return $this->toJson(); 1074 | } 1075 | 1076 | /** 1077 | * When a model is being unserialized, check if it needs to be booted. 1078 | * 1079 | * @return void 1080 | */ 1081 | public function __wakeup() 1082 | { 1083 | $this->bootIfNotBooted(); 1084 | } 1085 | 1086 | public function studly($value) 1087 | { 1088 | $value = ucwords(str_replace(['-', '_'], ' ', $value)); 1089 | 1090 | return str_replace(' ', '', $value); 1091 | } 1092 | 1093 | } 1094 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/ResthookService.php: -------------------------------------------------------------------------------- 1 | setUpdateVerb('put'); 16 | $this->setPrimaryKey('key'); 17 | parent::__construct($client); 18 | } 19 | 20 | public function events() 21 | { 22 | $data = $this->client->restfulRequest('get', $this->getFullUrl('event_keys')); 23 | $this->fill($data); 24 | 25 | return $this; 26 | } 27 | 28 | public function verify() 29 | { 30 | $data = $this->client->restfulRequest('post', $this->getFullUrl($this->key . '/verify')); 31 | $this->fill($data); 32 | 33 | return $this; 34 | } 35 | 36 | public function autoverify($return_header = true) 37 | { 38 | $headers = array(); 39 | foreach ($_SERVER as $key => $value) { 40 | if (substr($key, 0, 5) <> 'HTTP_') { 41 | continue; 42 | } 43 | $header = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5))))); 44 | $headers[$header] = $value; 45 | } 46 | 47 | if (isset($headers['X-Hook-Secret'])) { 48 | if ($return_header) { 49 | header('X-Hook-Secret: ' . $headers['X-Hook-Secret']); 50 | } else { 51 | return $headers['X-Hook-Secret']; 52 | } 53 | } 54 | 55 | return null; 56 | } 57 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/SubscriptionService.php: -------------------------------------------------------------------------------- 1 | client->restfulRequest('get', $this->getFullUrl($this->id . '/contacts'), $where); 29 | $this->fill($data); 30 | 31 | return $this; 32 | } 33 | 34 | public function removeContacts($contactIds) 35 | { 36 | if ( ! is_array($contactIds)) { 37 | throw new InfusionsoftException('Must be an array of contact ids'); 38 | } elseif (count($contactIds) > 100) { 39 | throw new InfusionsoftException('A maximum of 100 contact ids can be modified at once'); 40 | } 41 | 42 | $contactIds = ['ids' => implode(",", $contactIds)]; 43 | 44 | $response = $this->client->restfulRequest('delete', $this->getFullUrl($this->id . '/contacts'), $contactIds); 45 | 46 | return $response; 47 | } 48 | 49 | public function addContacts($contactIds) 50 | { 51 | if ( ! is_array($contactIds)) { 52 | throw new InfusionsoftException('Must be an array of contact ids'); 53 | } elseif (count($contactIds) > 100) { 54 | throw new InfusionsoftException('A maximum of 100 contact ids can be modified at once'); 55 | } 56 | 57 | $contacts = []; 58 | $contacts['ids'] = $contactIds; 59 | 60 | $response = $this->client->restfulRequest('post', $this->getFullUrl($this->id . '/contacts'), $contacts); 61 | 62 | return $response; 63 | } 64 | 65 | public function addCategory($name, $description) 66 | { 67 | 68 | $body = ['description' => $description, 'name' => $name]; 69 | 70 | $response = $this->client->restfulRequest('post', $this->getFullUrl('/categories'), $body); 71 | 72 | return $response; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/TaskService.php: -------------------------------------------------------------------------------- 1 | full_url.'/search'; 11 | 12 | return $url; 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/Rest/Traits/CannotCreate.php: -------------------------------------------------------------------------------- 1 | client->restfulRequest('get', $this->getIndexUrl()); 21 | 22 | return $data; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/SearchService.php: -------------------------------------------------------------------------------- 1 | client->request('SearchService.getAllReportColumns', $savedSearchId, $userId); 15 | } 16 | 17 | /** 18 | * @param integer $savedSearchId 19 | * @param integer $userId 20 | * @param integer $pageNumber 21 | * @return mixed 22 | */ 23 | public function getSavedSearchResultsAllFields($savedSearchId, $userId, $pageNumber) 24 | { 25 | return $this->client->request('SearchService.getSavedSearchResultsAllFields', $savedSearchId, $userId, $pageNumber); 26 | } 27 | 28 | /** 29 | * @param integer $savedSearchId 30 | * @param integer $userId 31 | * @param integer $pageNumber 32 | * @param array $returnFields 33 | * @return mixed 34 | */ 35 | public function getSavedSearchResults($savedSearchId, $userId, $pageNumber, $returnFields) 36 | { 37 | return $this->client->request('SearchService.getSavedSearchResults', $savedSearchId, $userId, $pageNumber, $returnFields); 38 | } 39 | 40 | /** 41 | * @param integer $userId 42 | * @return mixed 43 | */ 44 | public function getAvailableQuickSearches($userId) 45 | { 46 | return $this->client->request('SearchService.getAvailableQuickSearches', $userId); 47 | } 48 | 49 | /** 50 | * @param integer $quickSearchType 51 | * @param integer $userId 52 | * @param integer $searchData 53 | * @param integer $page 54 | * @param integer $returnLimit 55 | * @return mixed 56 | */ 57 | public function quickSearch($quickSearchType, $userId, $searchData, $page, $returnLimit) 58 | { 59 | return $this->client->request('SearchService.quickSearch', $quickSearchType, $userId, $searchData, $page, $returnLimit); 60 | } 61 | 62 | /** 63 | * @param integer $userId 64 | * @return mixed 65 | */ 66 | public function getDefaultQuickSearch($userId) 67 | { 68 | return $this->client->request('SearchService.getDefaultQuickSearch', $userId); 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/ShippingService.php: -------------------------------------------------------------------------------- 1 | client->request('ShippingService.getAllShippingOptions'); 13 | } 14 | 15 | /** 16 | * @param integer $optionId 17 | * @return mixed 18 | */ 19 | public function getFlatRateShippingOption($optionId) 20 | { 21 | return $this->client->request('ShippingService.getFlatRateShippingOption', $optionId); 22 | } 23 | 24 | /** 25 | * @param integer $optionId 26 | * @return mixed 27 | */ 28 | public function getOrderTotalShippingOption($optionId) 29 | { 30 | return $this->client->request('ShippingService.getOrderTotalShippingOption', $optionId); 31 | } 32 | 33 | /** 34 | * @param integer $optionId 35 | * @return mixed 36 | */ 37 | public function getOrderTotalShippingRanges($optionId) 38 | { 39 | return $this->client->request('ShippingService.getOrderTotalShippingRanges', $optionId); 40 | } 41 | 42 | /** 43 | * @param integer $optionId 44 | * @return mixed 45 | */ 46 | public function getProductBasedShippingOption($optionId) 47 | { 48 | return $this->client->request('ShippingService.getProductBasedShippingOption', $optionId); 49 | } 50 | 51 | /** 52 | * @param integer $optionId 53 | * @return mixed 54 | */ 55 | public function getOrderQuantityShippingOption($optionId) 56 | { 57 | return $this->client->request('ShippingService.getOrderQuantityShippingOption', $optionId); 58 | } 59 | 60 | /** 61 | * @param integer $optionId 62 | * @return mixed 63 | */ 64 | public function getWeightBasedShippingOption($optionId) 65 | { 66 | return $this->client->request('ShippingService.getWeightBasedShippingOption', $optionId); 67 | } 68 | 69 | /** 70 | * @param integer $optionId 71 | * @return mixed 72 | */ 73 | public function getUpsShippingOption($optionId) 74 | { 75 | return $this->client->request('ShippingService.getUpsShippingOption', $optionId); 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/WebFormService.php: -------------------------------------------------------------------------------- 1 | client->request('WebFormService.getMap'); 13 | } 14 | 15 | /** 16 | * @param integer $webFormId 17 | * @return mixed 18 | */ 19 | public function getHTML($webFormId) 20 | { 21 | return $this->client->request('WebFormService.getHTML', $webFormId); 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/Infusionsoft/Api/WebTrackingService.php: -------------------------------------------------------------------------------- 1 | client->request('WebTrackingService.getWebTrackingScriptTag'); 13 | } 14 | 15 | /** 16 | * @param integer $webFormId 17 | * @return mixed 18 | */ 19 | public function getWebTrackingScriptUrl($webFormId) 20 | { 21 | return $this->client->request('WebTrackingService.getWebTrackingScriptUrl'); 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/Infusionsoft/AuthenticationType.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom($config, 'infusionsoft'); 25 | $this->publishes([$config => config_path('infusionsoft.php')]); 26 | } 27 | 28 | /** 29 | * Register the service provider. 30 | * 31 | * @return void 32 | */ 33 | public function register() 34 | { 35 | $this->app->singleton('infusionsoft', function ($app) { 36 | 37 | return new Infusionsoft(config('infusionsoft')); 38 | 39 | }); 40 | } 41 | 42 | /** 43 | * Get the services provided by the provider. 44 | * 45 | * @return array 46 | */ 47 | public function provides() 48 | { 49 | return array('infusionsoft'); 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /src/Infusionsoft/FrameworkSupport/Laravel/config/config.php: -------------------------------------------------------------------------------- 1 | env('INFUSIONSOFT_CLIENT_ID'), 12 | 13 | 'clientSecret' => env('INFUSIONSOFT_SECRET'), 14 | 15 | 'redirectUri' => env('INFUSIONSOFT_REDIRECT_URL'), 16 | 17 | ); 18 | -------------------------------------------------------------------------------- /src/Infusionsoft/FrameworkSupport/Lumen/InfusionsoftServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->singleton('infusionsoft', function ($app) { 34 | 35 | $config = [ 36 | 'clientId' => env('INFUSIONSOFT_CLIENT_ID'), 37 | 'clientSecret' => env('INFUSIONSOFT_SECRET'), 38 | 'redirectUri' => env('INFUSIONSOFT_REDIRECT_URL'), 39 | ]; 40 | 41 | return new Infusionsoft($config); 42 | 43 | }); 44 | } 45 | 46 | /** 47 | * Get the services provided by the provider. 48 | * 49 | * @return array 50 | */ 51 | public function provides() 52 | { 53 | return array('infusionsoft'); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/Infusionsoft/Http/ArrayLogger.php: -------------------------------------------------------------------------------- 1 | logs; 16 | } 17 | 18 | /** 19 | * Logs with an arbitrary level. 20 | * 21 | * @param mixed $level 22 | * @param string|\Stringable $message 23 | * @param array $context 24 | * 25 | * @return void 26 | * 27 | * @throws \Psr\Log\InvalidArgumentException 28 | */ 29 | public function log($level, $message, array $context = array()): void 30 | { 31 | $this->logs[$level][] = [ 32 | 'message' => $message, 33 | 'context' => $context 34 | ]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Infusionsoft/Http/ClientInterface.php: -------------------------------------------------------------------------------- 1 | debug = $debug; 24 | $this->httpLogAdapter = $httpLogAdapter; 25 | 26 | $config = []; 27 | if(isset($options)) { 28 | $config = $options; 29 | } 30 | $config['timeout'] = 60; 31 | if ($this->debug) { 32 | $config['handler'] = HandlerStack::create(); 33 | $config['handler']->push( 34 | Middleware::log($this->httpLogAdapter, new MessageFormatter(MessageFormatter::DEBUG)) 35 | ); 36 | } 37 | 38 | parent::__construct($config); 39 | } 40 | 41 | /** 42 | * @return \fXmlRpc\Transport\TransportInterface 43 | */ 44 | public function getXmlRpcTransport($options = null) 45 | { 46 | 47 | $adapter = new \Http\Adapter\Guzzle7\Client($this); 48 | 49 | return new InfusionsoftHttpAdapterTransport( 50 | new \Http\Message\MessageFactory\DiactorosMessageFactory(), 51 | $adapter, 52 | $options 53 | ); 54 | } 55 | 56 | /** 57 | * Sends a request to the given URI and returns the raw response. 58 | * 59 | * @param string $method 60 | * @param string $uri 61 | * @param array $options 62 | * 63 | * @return mixed 64 | * @throws HttpException 65 | */ 66 | public function call($method, $uri = null, array $options = []) 67 | { 68 | if ( ! isset($options['headers'])) { 69 | $options['headers'] = []; 70 | } 71 | 72 | if ( ! isset($options['body'])) { 73 | $options['body'] = null; 74 | } 75 | 76 | try { 77 | $request = new Request($method, $uri, $options['headers'], $options['body']); 78 | $response = $this->send($request); 79 | 80 | return $response->getBody(); 81 | } catch (BadResponseException|ConnectException $e) { 82 | throw new HttpException($e->getMessage(), $e->getCode(), $e); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Infusionsoft/Http/HttpException.php: -------------------------------------------------------------------------------- 1 | client = $client; 25 | $this->messageFactory = $messageFactory; 26 | $this->defaultOptions = $options; 27 | } 28 | 29 | /** 30 | * @param $endpoint 31 | * @param $payload 32 | * @return string 33 | * @throws \Psr\Http\Client\ClientExceptionInterface 34 | */ 35 | public function send($endpoint, $payload) 36 | { 37 | $headers = []; 38 | if(isset($this->defaultOptions['headers'])) { 39 | $headers = $this->defaultOptions['headers']; 40 | } 41 | $headers['Content-Type'] = 'text/xml; charset=UTF-8'; 42 | 43 | try { 44 | $request = $this->messageFactory->createRequest( 45 | 'POST', 46 | $endpoint, 47 | $headers, 48 | $payload 49 | ); 50 | 51 | $response = $this->client->sendRequest($request); 52 | if ($response->getStatusCode() !== 200) { 53 | throw HttpException::httpError($response->getReasonPhrase(), $response->getStatusCode()); 54 | } 55 | 56 | return (string) $response->getBody(); 57 | 58 | } catch (PsrHttpException $e) { 59 | $response = $e->getResponse(); 60 | throw HttpException::httpError($response->getReasonPhrase(), $response->getStatusCode()); 61 | } catch (ClientException $e) { 62 | throw TransportException::transportError($e); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/Infusionsoft/Http/InfusionsoftSerializer.php: -------------------------------------------------------------------------------- 1 | getXmlRpcTransport(); 26 | 27 | $parser = new XmlReaderParser(true); 28 | 29 | $client = new Client($uri, $transport, $parser); 30 | 31 | $response = $client->call($method, $params); 32 | 33 | return $response; 34 | } 35 | catch (fXmlRpcException $e) 36 | { 37 | throw new HttpException($e->getMessage(), $e->getCode(), $e); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/Infusionsoft/Http/SerializerInterface.php: -------------------------------------------------------------------------------- 1 | clientId = $config['clientId']; 102 | } 103 | 104 | if (isset($config['clientSecret'])) { 105 | $this->clientSecret = $config['clientSecret']; 106 | } 107 | 108 | if (isset($config['clientId']) && isset($config['clientSecret'])) { 109 | $this->authenticationType = AuthenticationType::OAuth2AccessToken; 110 | } else if (isset($config['apikey'])) { 111 | $this->apikey = $config['apikey']; 112 | 113 | if ( substr_compare($this->apikey, 'KeapAK', 0, strlen('KeapAK') ) === 0) { 114 | $this->authenticationType = AuthenticationType::ServiceAccountKey; 115 | } else { 116 | $this->authenticationType = AuthenticationType::LegacyKey; 117 | } 118 | } else { 119 | throw new Exception('Constructor needs either a clientId & clientSecret or an apikey'); 120 | } 121 | 122 | if (isset($config['redirectUri'])) { 123 | $this->redirectUri = $config['redirectUri']; 124 | } 125 | 126 | if (isset($config['debug'])) { 127 | $this->debug = $config['debug']; 128 | } 129 | } 130 | 131 | /** 132 | * @return string 133 | */ 134 | public function getUrl() 135 | { 136 | return $this->url; 137 | } 138 | 139 | /** 140 | * @param string $url 141 | * 142 | * @return Infusionsoft 143 | */ 144 | public function setUrl($url) 145 | { 146 | $this->url = $url; 147 | 148 | return $this; 149 | } 150 | 151 | /** 152 | * @return string 153 | */ 154 | public function getBaseUrl() 155 | { 156 | return $this->baseUri; 157 | } 158 | 159 | /** 160 | * @param string 161 | * 162 | * @return Infusionsoft 163 | */ 164 | public function setBaseUrl($url) 165 | { 166 | $this->baseUri = $url; 167 | 168 | return $this; 169 | } 170 | 171 | /** 172 | * @return string 173 | */ 174 | public function getAuth() 175 | { 176 | return $this->auth; 177 | } 178 | 179 | /** 180 | * @param string $auth 181 | * 182 | * @return Infusionsoft 183 | */ 184 | public function setAuth($auth) 185 | { 186 | $this->auth = $auth; 187 | 188 | return $this; 189 | } 190 | 191 | /** 192 | * @return string 193 | */ 194 | public function getTokenUri() 195 | { 196 | return $this->tokenUri; 197 | } 198 | 199 | /** 200 | * @param string $tokenUri 201 | */ 202 | public function setTokenUri($tokenUri) 203 | { 204 | $this->tokenUri = $tokenUri; 205 | } 206 | 207 | /** 208 | * @return string 209 | */ 210 | public function getClientId() 211 | { 212 | return $this->clientId; 213 | } 214 | 215 | /** 216 | * @param string $clientId 217 | * 218 | * @return Infusionsoft 219 | */ 220 | public function setClientId($clientId) 221 | { 222 | $this->clientId = $clientId; 223 | 224 | return $this; 225 | } 226 | 227 | /** 228 | * @return string 229 | */ 230 | public function getClientSecret() 231 | { 232 | return $this->clientSecret; 233 | } 234 | 235 | /** 236 | * @param string $clientSecret 237 | * 238 | * @return Infusionsoft 239 | */ 240 | public function setClientSecret($clientSecret) 241 | { 242 | $this->clientSecret = $clientSecret; 243 | 244 | return $this; 245 | } 246 | 247 | /** 248 | * @return string 249 | */ 250 | public function getRedirectUri() 251 | { 252 | return $this->redirectUri; 253 | } 254 | 255 | /** 256 | * @param string $redirectUri 257 | * 258 | * @return Infusionsoft 259 | */ 260 | public function setRedirectUri($redirectUri) 261 | { 262 | $this->redirectUri = $redirectUri; 263 | 264 | return $this; 265 | } 266 | 267 | /** 268 | * @return string 269 | */ 270 | public function getAuthorizationUrl($state = null) 271 | { 272 | $params = array( 273 | 'client_id' => $this->clientId, 274 | 'redirect_uri' => $this->redirectUri, 275 | 'response_type' => 'code', 276 | 'scope' => 'full' 277 | ); 278 | 279 | if ( ! is_null($state) && $state !== null && is_string($state)) { 280 | $params['state'] = (string)$state; 281 | } 282 | 283 | return $this->auth . '?' . http_build_query($params); 284 | } 285 | 286 | /** 287 | * @return Infusionsoft 288 | */ 289 | public function setApiKey($apikey) { 290 | $this->apikey = $apikey; 291 | 292 | return $this; 293 | } 294 | 295 | /** 296 | * @return string 297 | */ 298 | public function getApiKey() { 299 | return $this->apikey; 300 | } 301 | 302 | /** 303 | * @param string $code 304 | * 305 | * @return array 306 | * @throws InfusionsoftException 307 | */ 308 | public function requestAccessToken($code) 309 | { 310 | $params = array( 311 | 'client_id' => $this->clientId, 312 | 'client_secret' => $this->clientSecret, 313 | 'code' => $code, 314 | 'grant_type' => 'authorization_code', 315 | 'redirect_uri' => $this->redirectUri, 316 | ); 317 | 318 | $client = $this->getHttpClient(); 319 | 320 | $tokenInfo = $client->call('POST', $this->tokenUri, [ 321 | 'body' => http_build_query($params), 322 | 'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'] 323 | ]); 324 | 325 | $this->setToken(new Token(json_decode($tokenInfo, true))); 326 | 327 | return $this->getToken(); 328 | } 329 | 330 | /** 331 | * @return Http\ClientInterface 332 | */ 333 | public function getHttpClient($options = null) 334 | { 335 | if ( ! $this->httpClient) { 336 | return new Http\GuzzleHttpClient($this->debug, $this->getHttpLogAdapter(), $options); 337 | } 338 | 339 | return $this->httpClient; 340 | } 341 | 342 | /** 343 | * @return array 344 | * @throws InfusionsoftException 345 | */ 346 | public function refreshAccessToken() 347 | { 348 | $headers = array( 349 | 'Authorization' => 'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret), 350 | 'Content-Type' => 'application/x-www-form-urlencoded' 351 | ); 352 | 353 | $params = array( 354 | 'grant_type' => 'refresh_token', 355 | 'refresh_token' => $this->getToken()->getRefreshToken(), 356 | ); 357 | 358 | $client = $this->getHttpClient(); 359 | 360 | $tokenInfo = $client->call('POST', $this->tokenUri, 361 | ['body' => http_build_query($params), 'headers' => $headers]); 362 | 363 | $this->setToken(new Token(json_decode($tokenInfo, true))); 364 | 365 | return $this->getToken(); 366 | } 367 | 368 | /** 369 | * @return Token 370 | */ 371 | public function getToken() 372 | { 373 | return $this->token; 374 | } 375 | 376 | /** 377 | * @param Token $token 378 | */ 379 | public function setToken($token) 380 | { 381 | $this->token = $token; 382 | } 383 | 384 | /** 385 | * @param Http\ClientInterface $client 386 | */ 387 | public function setHttpClient($client) 388 | { 389 | $this->httpClient = $client; 390 | } 391 | 392 | /** 393 | * @return Http\SerializerInterface 394 | */ 395 | public function getSerializer() 396 | { 397 | if ( ! $this->serializer) { 398 | return new Http\InfusionsoftSerializer(); 399 | } 400 | 401 | return $this->serializer; 402 | } 403 | 404 | /** 405 | * @param Http\SerializerInterface $serializer 406 | */ 407 | public function setSerializer(Http\SerializerInterface $serializer) 408 | { 409 | $this->serializer = $serializer; 410 | } 411 | 412 | /** 413 | * @return LoggerInterface 414 | */ 415 | public function getHttpLogAdapter() 416 | { 417 | // If a log adapter hasn't been set, we default to the null adapter 418 | if ( ! $this->httpLogAdapter) { 419 | $this->httpLogAdapter = new ArrayLogger(); 420 | } 421 | 422 | return $this->httpLogAdapter; 423 | } 424 | 425 | /** 426 | * @param LoggerInterface $httpLogAdapter 427 | * 428 | * @return \Infusionsoft\Infusionsoft 429 | */ 430 | public function setHttpLogAdapter(LoggerInterface $httpLogAdapter) 431 | { 432 | $this->httpLogAdapter = $httpLogAdapter; 433 | 434 | return $this; 435 | } 436 | 437 | /** 438 | * @return array 439 | */ 440 | public function getLogs() 441 | { 442 | if ( ! $this->debug) { 443 | return array(); 444 | } 445 | 446 | $logger = $this->getHttpLogAdapter(); 447 | if ( ! $logger instanceof ArrayLogger) { 448 | return array(); 449 | } 450 | 451 | return $logger->getLogs(); 452 | } 453 | 454 | /** 455 | * Checks if the current token is null or expired 456 | * 457 | * @return boolean 458 | */ 459 | public function isTokenExpired() 460 | { 461 | $token = $this->getToken(); 462 | 463 | if ( ! is_object($token)) { 464 | return true; 465 | } 466 | 467 | return $token->isExpired(); 468 | } 469 | 470 | /** 471 | * @throws InfusionsoftException 472 | * @return mixed 473 | */ 474 | public function request() 475 | { 476 | // Before making the request, we can make sure that the token is still 477 | // valid by doing a check on the end of life. 478 | $token = $this->getToken(); 479 | if ($this->authenticationType === AuthenticationType::OAuth2AccessToken && $this->isTokenExpired()) { 480 | throw new TokenExpiredException; 481 | } 482 | 483 | $params = func_get_args(); 484 | $method = array_shift($params); 485 | 486 | // Some older methods in the API require a key parameter to be sent 487 | // even if OAuth is being used. This flag can be made false as it 488 | // will break some newer endpoints. 489 | if ($this->needsEmptyKey) { 490 | $params = array_merge(array('key' => 'backwards-compatability'), $params); 491 | } 492 | 493 | // Reset the empty key flag back to the default for the next request 494 | $this->needsEmptyKey = true; 495 | 496 | $options = $this->setOptionsForRequest([]); 497 | 498 | $client = $this->getSerializer(); 499 | 500 | return $client->request($method, $this->getUrl(), $params, $this->getHttpClient($options)); 501 | } 502 | 503 | /** 504 | * @param string $method 505 | * @param string $url 506 | * @param array $params 507 | * 508 | * @throws InfusionsoftException 509 | * @return mixed 510 | */ 511 | public function restfulRequest($method, $url, $params = array()) 512 | { 513 | // Before making the request, we can make sure that the token is still 514 | // valid by doing a check on the end of life. 515 | if ($this->authenticationType === AuthenticationType::OAuth2AccessToken && $this->isTokenExpired()) { 516 | throw new TokenExpiredException; 517 | } 518 | 519 | $client = $this->getHttpClient(); 520 | 521 | if (strtolower($method) === 'get' || strtolower($method) === 'delete') { 522 | $url = $url . '?' . http_build_query($params); 523 | } else { 524 | $params['body'] = json_encode($params); 525 | } 526 | 527 | $params = $this->setOptionsForRequest($params); 528 | 529 | $response = (string)$client->call($method, $url, $params); 530 | 531 | return json_decode($response, true); 532 | } 533 | 534 | /** 535 | * @param boolean $debug 536 | * 537 | * @return \Infusionsoft\Infusionsoft 538 | */ 539 | public function setDebug($debug) 540 | { 541 | $this->debug = (bool)$debug; 542 | 543 | return $this; 544 | } 545 | 546 | /** 547 | * @param \DateTime|string $datetime 548 | * 549 | * @throws \Exception 550 | * @return string 551 | */ 552 | public function formatDate($datetime = 'now') 553 | { 554 | if ( ! $datetime instanceof \DateTime) { 555 | $datetime = new \DateTime($datetime, new \DateTimeZone('America/New_York')); 556 | } 557 | 558 | return $datetime->format('Y-m-d\TH:i:s'); 559 | } 560 | 561 | /** 562 | * @param $name 563 | * 564 | * @throws \UnexpectedValueException 565 | * @return mixed 566 | */ 567 | public function __get($name) 568 | { 569 | $services = array( 570 | 'affiliatePrograms', 571 | 'affiliates', 572 | 'contacts', 573 | 'data', 574 | 'discounts', 575 | 'emails', 576 | 'files', 577 | 'funnels', 578 | 'invoices', 579 | 'merchants', 580 | 'orders', 581 | 'products', 582 | 'search', 583 | 'tags', 584 | 'shipping', 585 | 'webForms', 586 | 'webTracking' 587 | ); 588 | 589 | if (method_exists($this, $name) and in_array($name, $services)) { 590 | return $this->{$name}(); 591 | } 592 | 593 | throw new \UnexpectedValueException(sprintf('Invalid property: %s', $name)); 594 | } 595 | 596 | /** 597 | * @return \Infusionsoft\Api\AffiliateProgramService 598 | */ 599 | public function affiliatePrograms() 600 | { 601 | return $this->getApi('AffiliateProgramService'); 602 | } 603 | 604 | /** 605 | * @return \Infusionsoft\Api\AffiliateService 606 | */ 607 | public function affiliates() 608 | { 609 | return $this->getApi('AffiliateService'); 610 | } 611 | 612 | /** 613 | * @param string $api 614 | * 615 | * @return \Infusionsoft\Api\ContactService | \Infusionsoft\Api\Rest\ContactService 616 | */ 617 | public function contacts($api = 'rest') 618 | { 619 | if ($api == 'xml') { 620 | return $this->getApi('ContactService'); 621 | } 622 | 623 | return $this->getRestApi('ContactService'); 624 | } 625 | 626 | /** 627 | * @return \Infusionsoft\Api\DataService 628 | */ 629 | public function data() 630 | { 631 | return $this->getApi('DataService'); 632 | } 633 | 634 | /** 635 | * @return \Infusionsoft\Api\DiscountService 636 | */ 637 | public function discounts() 638 | { 639 | return $this->getApi('DiscountService'); 640 | } 641 | 642 | /** 643 | * @return \Infusionsoft\Api\CreditCardSubmissionService 644 | */ 645 | public function creditcards() 646 | { 647 | return $this->getApi('CreditCardSubmissionService'); 648 | } 649 | 650 | /** 651 | * @param string $api 652 | * 653 | * @return \Infusionsoft\Api\APIEmailService | \Infusionsoft\Api\Rest\EmailService 654 | */ 655 | public function emails($api = 'rest') 656 | { 657 | if ($api == 'xml') { 658 | return $this->getApi('APIEmailService'); 659 | } 660 | 661 | return $this->getRestApi('EmailService'); 662 | } 663 | 664 | /** 665 | * @param string $api 666 | * 667 | * @return \Infusionsoft\Api\FileService | \Infusionsoft\Api\Rest\FileService 668 | */ 669 | public function files($api = 'rest') 670 | { 671 | if ($api == 'xml') { 672 | return $this->getApi('FileService'); 673 | } 674 | 675 | return $this->getRestApi('FileService'); 676 | } 677 | 678 | /** 679 | * @return \Infusionsoft\Api\FunnelService 680 | */ 681 | public function funnels() 682 | { 683 | return $this->getApi('FunnelService'); 684 | } 685 | 686 | /** 687 | * @return \Infusionsoft\Api\InvoiceService 688 | */ 689 | public function invoices() 690 | { 691 | return $this->getApi('InvoiceService'); 692 | } 693 | 694 | /** 695 | * @return \Infusionsoft\Api\Rest\MerchantService 696 | */ 697 | public function merchants() 698 | { 699 | return $this->getRestApi('MerchantService'); 700 | } 701 | 702 | /** 703 | * @param string $api 704 | * 705 | * @return \Infusionsoft\Api\OrderService | \Infusionsoft\Api\Rest\OrderService 706 | */ 707 | public function orders($api = 'rest') 708 | { 709 | if ($api == 'xml') { 710 | return $this->getApi('OrderService'); 711 | } 712 | 713 | return $this->getRestApi('OrderService'); 714 | } 715 | 716 | /** 717 | * @param string $api 718 | * 719 | * @return \Infusionsoft\Api\ProductService | \Infusionsoft\Api\Rest\ProductService 720 | */ 721 | public function products($api = 'rest') 722 | { 723 | if ($api == 'xml') { 724 | return $this->getApi('ProductService'); 725 | } 726 | 727 | return $this->getRestApi('ProductService'); 728 | } 729 | 730 | /** 731 | * @return \Infusionsoft\Api\Rest\ResthookService 732 | */ 733 | public function resthooks() 734 | { 735 | return $this->getRestApi('ResthookService'); 736 | } 737 | 738 | /** 739 | * @return \Infusionsoft\Api\SearchService 740 | */ 741 | public function search() 742 | { 743 | return $this->getApi('SearchService'); 744 | } 745 | 746 | /** 747 | * @return \Infusionsoft\Api\ShippingService 748 | */ 749 | public function shipping() 750 | { 751 | return $this->getApi('ShippingService'); 752 | } 753 | 754 | /** 755 | * @return \Infusionsoft\Api\WebFormService 756 | */ 757 | public function webForms() 758 | { 759 | return $this->getApi('WebFormService'); 760 | } 761 | 762 | /** 763 | * @return \Infusionsoft\Api\WebTrackingService 764 | */ 765 | public function webTracking() 766 | { 767 | return $this->getApi('WebTrackingService'); 768 | } 769 | 770 | /** 771 | * @return \Infusionsoft\Api\Rest\TaskService 772 | */ 773 | public function tasks() 774 | { 775 | return $this->getRestApi('TaskService'); 776 | } 777 | 778 | /** 779 | * @return \Infusionsoft\Api\Rest\NoteService 780 | */ 781 | public function notes() 782 | { 783 | return $this->getRestApi('NoteService'); 784 | } 785 | 786 | /** 787 | * @return \Infusionsoft\Api\Rest\AppointmentService 788 | */ 789 | public function appointments() 790 | { 791 | return $this->getRestApi('AppointmentService'); 792 | } 793 | 794 | /** 795 | * @return \Infusionsoft\Api\Rest\CustomFieldService 796 | */ 797 | public function customfields() 798 | { 799 | return $this->getRestApi('CustomFieldService'); 800 | } 801 | 802 | /** 803 | * @return \Infusionsoft\Api\Rest\TagService 804 | */ 805 | public function tags() 806 | { 807 | return $this->getRestApi('TagService'); 808 | } 809 | 810 | /** 811 | * @return \Infusionsoft\Api\Rest\TransactionService 812 | */ 813 | public function transactions() 814 | { 815 | return $this->getRestApi('TransactionService'); 816 | } 817 | 818 | /** 819 | * @return \Infusionsoft\Api\Rest\CampaignService 820 | */ 821 | public function campaigns() 822 | { 823 | return $this->getRestApi('CampaignService'); 824 | } 825 | 826 | /** 827 | * @return \Infusionsoft\Api\Rest\CampaignService 828 | */ 829 | public function companies() 830 | { 831 | return $this->getRestApi('CompanyService'); 832 | } 833 | 834 | /** 835 | * @return \Infusionsoft\Api\Rest\UserInfoService 836 | */ 837 | public function userinfo() 838 | { 839 | return $this->getRestApi('UserInfoService'); 840 | } 841 | 842 | /** 843 | * @return \Infusionsoft\Api\Rest\OpportunityService 844 | */ 845 | public function opportunities() 846 | { 847 | return $this->getRestApi('OpportunityService'); 848 | } 849 | 850 | /** 851 | * @return \Infusionsoft\Api\Rest\SubscriptionService 852 | */ 853 | public function subscriptions() 854 | { 855 | return $this->getRestApi('SubscriptionService'); 856 | } 857 | 858 | /** 859 | * Returns the requested class name, optionally using a cached array so no 860 | * object is instantiated more than once during a request. 861 | * 862 | * @param string $class 863 | * 864 | * @return mixed 865 | */ 866 | public function getApi($class) 867 | { 868 | $class = '\Infusionsoft\Api\\' . $class; 869 | 870 | if ( ! array_key_exists($class, $this->apis)) { 871 | $this->apis[$class] = new $class($this); 872 | } 873 | 874 | return $this->apis[$class]; 875 | } 876 | 877 | /** 878 | * Returns the requested class name, optionally using a cached array so no 879 | * object is instantiated more than once during a request. 880 | * 881 | * @param string $class 882 | * 883 | * @return mixed 884 | */ 885 | public function getRestApi($class) 886 | { 887 | $class = '\Infusionsoft\Api\Rest\\' . $class; 888 | 889 | return new $class($this); 890 | } 891 | 892 | /** 893 | * @param array $options 894 | * @return array 895 | */ 896 | public function setOptionsForRequest(array $options): array 897 | { 898 | if ($this->authenticationType === AuthenticationType::OAuth2AccessToken) { 899 | $options['headers'] = array( 900 | 'Content-Type' => 'application/json', 901 | 'Authorization' => 'Bearer ' . $this->getToken()->getAccessToken() 902 | ); 903 | } else { 904 | $options['headers'] = array( 905 | 'Content-Type' => 'application/json', 906 | 'X-Keap-API-Key' => $this->apikey 907 | ); 908 | } 909 | return $options; 910 | } 911 | 912 | } 913 | 914 | -------------------------------------------------------------------------------- /src/Infusionsoft/InfusionsoftCollection.php: -------------------------------------------------------------------------------- 1 | items = is_array($items) ? $items : $this->getArrayableItems($items); 27 | } 28 | 29 | /** 30 | * Create a new collection instance if the value isn't one already. 31 | * 32 | * @param mixed $items 33 | * @return static 34 | */ 35 | public static function make($items = []) 36 | { 37 | return new static($items); 38 | } 39 | 40 | /** 41 | * Get all of the items in the collection. 42 | * 43 | * @return array 44 | */ 45 | public function all() 46 | { 47 | return $this->items; 48 | } 49 | 50 | /** 51 | * Get an item from the collection by key. 52 | * 53 | * @param mixed $key 54 | * @param mixed $default 55 | * @return mixed 56 | */ 57 | public function get($key, $default = null) 58 | { 59 | if ($this->offsetExists($key)) { 60 | return $this->items[$key]; 61 | } 62 | 63 | return value($default); 64 | } 65 | 66 | /** 67 | * Determine if an item exists in the collection by key. 68 | * 69 | * @param mixed $key 70 | * @return bool 71 | */ 72 | public function has($key) 73 | { 74 | return $this->offsetExists($key); 75 | } 76 | 77 | /** 78 | * Determine if the collection is empty or not. 79 | * 80 | * @return bool 81 | */ 82 | public function isEmpty() 83 | { 84 | return empty($this->items); 85 | } 86 | 87 | /** 88 | * Get the keys of the collection items. 89 | * 90 | * @return static 91 | */ 92 | public function keys() 93 | { 94 | return new static(array_keys($this->items)); 95 | } 96 | 97 | /** 98 | * Get the collection of items as a plain array. 99 | * 100 | * @return array 101 | */ 102 | public function toArray() 103 | { 104 | return array_map(function ($value) { 105 | return $value instanceof Arrayable ? $value->toArray() : $value; 106 | 107 | }, $this->items); 108 | } 109 | 110 | /** 111 | * Convert the object into something JSON serializable. 112 | * 113 | * @return array 114 | */ 115 | public function jsonSerialize() 116 | { 117 | return $this->toArray(); 118 | } 119 | 120 | /** 121 | * Get the collection of items as JSON. 122 | * 123 | * @param int $options 124 | * @return string 125 | */ 126 | public function toJson($options = 0) 127 | { 128 | return json_encode($this->toArray(), $options); 129 | } 130 | 131 | /** 132 | * Count the number of items in the collection. 133 | * 134 | * @return int 135 | */ 136 | public function count() 137 | { 138 | return count($this->items); 139 | } 140 | 141 | /** 142 | * Determine if an item exists at an offset. 143 | * 144 | * @param mixed $key 145 | * @return bool 146 | */ 147 | public function offsetExists($key) 148 | { 149 | return array_key_exists($key, $this->items); 150 | } 151 | 152 | /** 153 | * Get an item at a given offset. 154 | * 155 | * @param mixed $key 156 | * @return mixed 157 | */ 158 | public function offsetGet($key) 159 | { 160 | return $this->items[$key]; 161 | } 162 | 163 | /** 164 | * Set the item at a given offset. 165 | * 166 | * @param mixed $key 167 | * @param mixed $value 168 | * @return void 169 | */ 170 | public function offsetSet($key, $value) 171 | { 172 | if (is_null($key)) { 173 | $this->items[] = $value; 174 | } else { 175 | $this->items[$key] = $value; 176 | } 177 | } 178 | 179 | /** 180 | * Unset the item at a given offset. 181 | * 182 | * @param string $key 183 | * @return void 184 | */ 185 | public function offsetUnset($key) 186 | { 187 | unset($this->items[$key]); 188 | } 189 | 190 | /** 191 | * Convert the collection to its string representation. 192 | * 193 | * @return string 194 | */ 195 | public function __toString() 196 | { 197 | return $this->toJson(); 198 | } 199 | 200 | /** 201 | * Results array of items from Collection or Arrayable. 202 | * 203 | * @param mixed $items 204 | * @return array 205 | */ 206 | protected function getArrayableItems($items) 207 | { 208 | if ($items instanceof self) { 209 | return $items->all(); 210 | } elseif ($items instanceof Arrayable) { 211 | return $items->toArray(); 212 | } elseif ($items instanceof Jsonable) { 213 | return json_decode($items->toJson(), true); 214 | } 215 | 216 | return (array) $items; 217 | } 218 | 219 | } -------------------------------------------------------------------------------- /src/Infusionsoft/InfusionsoftException.php: -------------------------------------------------------------------------------- 1 | setAccessToken($data['access_token']); 35 | unset($data['access_token']); 36 | } 37 | 38 | if (isset($data['refresh_token'])) 39 | { 40 | $this->setRefreshToken($data['refresh_token']); 41 | unset($data['refresh_token']); 42 | } 43 | 44 | if (isset($data['expires_in'])) 45 | { 46 | $this->setEndOfLife(time() + $data['expires_in']); 47 | unset($data['expires_in']); 48 | } 49 | 50 | if (count($data) > 0) 51 | { 52 | $this->setExtraInfo($data); 53 | } 54 | } 55 | 56 | /** 57 | * @return string 58 | */ 59 | public function getAccessToken() 60 | { 61 | return $this->accessToken; 62 | } 63 | 64 | /** 65 | * @param string $accessToken 66 | */ 67 | public function setAccessToken($accessToken) 68 | { 69 | $this->accessToken = $accessToken; 70 | } 71 | 72 | /** 73 | * @return int 74 | */ 75 | public function getEndOfLife() 76 | { 77 | return $this->endOfLife; 78 | } 79 | 80 | /** 81 | * @param int $endOfLife 82 | */ 83 | public function setEndOfLife($endOfLife) 84 | { 85 | $this->endOfLife = $endOfLife; 86 | } 87 | 88 | /** 89 | * @return string 90 | */ 91 | public function getRefreshToken() 92 | { 93 | return $this->refreshToken; 94 | } 95 | 96 | /** 97 | * @param string $refreshToken 98 | */ 99 | public function setRefreshToken($refreshToken) 100 | { 101 | $this->refreshToken = $refreshToken; 102 | } 103 | 104 | /** 105 | * @return array 106 | */ 107 | public function getExtraInfo() 108 | { 109 | return $this->extraInfo; 110 | } 111 | 112 | /** 113 | * @param array $extraInfo 114 | */ 115 | public function setExtraInfo($extraInfo) 116 | { 117 | $this->extraInfo = $extraInfo; 118 | } 119 | 120 | /** 121 | * Checks if the token is expired 122 | * 123 | * @return boolean 124 | */ 125 | public function isExpired() 126 | { 127 | return ($this->getEndOfLife() < time()); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/Infusionsoft/TokenExpiredException.php: -------------------------------------------------------------------------------- 1 | ifs = new Infusionsoft(array( 20 | 'clientId' => 'foo', 21 | 'clientSecret' => 'bar', 22 | 'redirectUri' => 'http://example.com/' 23 | )); 24 | } 25 | 26 | public function testMainClass() 27 | { 28 | $this->assertInstanceOf('Infusionsoft\Infusionsoft', $this->ifs); 29 | } 30 | 31 | public function testInfusionsoft() 32 | { 33 | $this->assertEquals('foo', $this->ifs->getClientId()); 34 | $this->assertEquals('bar', $this->ifs->getClientSecret()); 35 | $this->assertEquals('http://example.com/', $this->ifs->getRedirectUri()); 36 | } 37 | 38 | public function testGetAuthorizationUrl() 39 | { 40 | $this->assertEquals('https://signin.infusionsoft.com/app/oauth/authorize?client_id=foo&redirect_uri=http%3A%2F%2Fexample.com%2F&response_type=code&scope=full', 41 | $this->ifs->getAuthorizationUrl()); 42 | } 43 | 44 | /** 45 | * @dataProvider dataStates 46 | * 47 | * @param $state 48 | */ 49 | public function testGetAuthorizationUrlWithState($state) 50 | { 51 | $this->assertEquals('https://signin.infusionsoft.com/app/oauth/authorize?client_id=foo&redirect_uri=http%3A%2F%2Fexample.com%2F&response_type=code&scope=full&state=' . $state, 52 | $this->ifs->getAuthorizationUrl((string)$state)); 53 | } 54 | 55 | public static function dataStates() 56 | { 57 | return [ 58 | [0], 59 | ['0'], 60 | ['08a4840e421bdea6'] 61 | ]; 62 | } 63 | 64 | public function testSettingUrl() 65 | { 66 | $this->ifs->setUrl('http://example.com/'); 67 | $this->assertEquals('http://example.com/', $this->ifs->getUrl()); 68 | } 69 | 70 | public function testSettingAuth() 71 | { 72 | $this->ifs->setAuth('http://example.com/'); 73 | $this->assertEquals('http://example.com/', $this->ifs->getAuth()); 74 | } 75 | 76 | public function testSettingTokenUri() 77 | { 78 | $this->ifs->setTokenUri('http://example.com/'); 79 | $this->assertEquals('http://example.com/', $this->ifs->getTokenUri()); 80 | } 81 | 82 | public function testSettingToken() 83 | { 84 | $this->ifs->setToken('http://example.com/'); 85 | $this->assertEquals('http://example.com/', $this->ifs->getToken()); 86 | } 87 | 88 | public function testDefaultHttpLogAdapter() 89 | { 90 | $this->assertInstanceOf('Infusionsoft\Http\ArrayLogger', $this->ifs->getHttpLogAdapter()); 91 | } 92 | 93 | public function testSettingClientId() 94 | { 95 | $this->ifs->setClientId('foo'); 96 | $this->assertEquals('foo', $this->ifs->getClientId()); 97 | } 98 | 99 | public function testSettingClientSecret() 100 | { 101 | $this->ifs->setClientSecret('bar'); 102 | $this->assertEquals('bar', $this->ifs->getClientSecret()); 103 | } 104 | 105 | public function testSettingRedirectUri() 106 | { 107 | $this->ifs->setRedirectUri('http://example.com/'); 108 | $this->assertEquals('http://example.com/', $this->ifs->getRedirectUri()); 109 | } 110 | 111 | public function testSettingTokenAndGettingProperties() 112 | { 113 | $this->ifs->setToken(new Token(array( 114 | 'access_token' => 'foo', 115 | 'refresh_token' => 'bar', 116 | 'expires_in' => 1, 117 | 'key' => 'value' 118 | ))); 119 | $this->assertEquals('foo', $this->ifs->getToken()->getAccessToken()); 120 | $this->assertEquals('bar', $this->ifs->getToken()->getRefreshToken()); 121 | $this->assertEquals(time() + 1, $this->ifs->getToken()->getEndOfLife()); 122 | $extra = $this->ifs->getToken()->getExtraInfo(); 123 | $this->assertEquals('value', $extra['key']); 124 | } 125 | 126 | public function testSettingHttpLogAdapter() 127 | { 128 | 129 | $this->ifs->setHttpLogAdapter(new NullLogger()); 130 | $this->assertInstanceOf('Psr\Log\NullLogger', $this->ifs->getHttpLogAdapter()); 131 | } 132 | 133 | public function testDefaultHttpClientShouldBeGuzzle() 134 | { 135 | $this->assertInstanceOf('Infusionsoft\Http\GuzzleHttpClient', $this->ifs->getHttpClient()); 136 | } 137 | 138 | public function testRequestingAccessTokenSetsAccessToken() 139 | { 140 | $client = m::mock('Infusionsoft\Http\GuzzleHttpClient'); 141 | $client->shouldReceive('call')->once()->withAnyArgs()->andReturn(json_encode(['access_token' => 'access_token'])); 142 | 143 | $this->ifs->setClientId('foo'); 144 | $this->ifs->setClientSecret('bar'); 145 | $this->ifs->setRedirectUri('baz'); 146 | $this->ifs->setHttpClient($client); 147 | $this->ifs->requestAccessToken('code'); 148 | $this->assertEquals('access_token', $this->ifs->getToken()->getAccessToken()); 149 | } 150 | 151 | public function testIsTokenExpired() 152 | { 153 | //no token is set so it should return true 154 | $this->assertTrue($this->ifs->isTokenExpired()); 155 | 156 | //token is set and still not expired 157 | $token = new Token(array('access_token' => '', 'refresh_token' => '', 'expires_in' => 5)); 158 | $this->ifs->setToken($token); 159 | $this->assertFalse($this->ifs->isTokenExpired()); 160 | 161 | //token is set but expired 162 | $token = new Token(array('access_token' => '', 'refresh_token' => '', 'expires_in' => -5)); 163 | $this->ifs->setToken($token); 164 | $this->assertTrue($this->ifs->isTokenExpired()); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /tests/Infusionsoft/RestModelTest.php: -------------------------------------------------------------------------------- 1 | client = m::mock('Infusionsoft\Infusionsoft'); 19 | $this->model = new ContactService($this->client); 20 | } 21 | 22 | public function testFirst() { 23 | $this->mockRestfulRequest([ 24 | 'get', 25 | 'https://api.infusionsoft.com/crm/rest/v1/contacts', 26 | ['limit' => 1], 27 | ], 28 | [ 29 | 'count' => 1, 30 | 'contacts' => [['first_name' => 'Bob']], 31 | ]); 32 | 33 | $this->assertEquals( 34 | 'Bob', 35 | $this->model->first()->first_name 36 | ); 37 | } 38 | 39 | public function testFirstWithClauses() { 40 | $this->mockRestfulRequest([ 41 | 'get', 42 | 'https://api.infusionsoft.com/crm/rest/v1/contacts', 43 | [ 44 | // params should be folded in 45 | 'limit' => 1, 46 | 'optional_properties' => 'custom_fields,job_title', 47 | 'email' => 'bob@example.com', 48 | ], 49 | ], 50 | [ 51 | 'count' => 1, 52 | 'contacts' => [['first_name' => 'Bob']], 53 | ]); 54 | 55 | $bob = $this->model 56 | ->where('email', 'bob@example.com') 57 | ->with(['custom_fields', 'job_title']) 58 | ->first(); 59 | 60 | $this->assertEquals( 61 | 'Bob', 62 | $bob->first_name 63 | ); 64 | 65 | } 66 | 67 | protected function mockRestfulRequest($args = [], $return = []) { 68 | $this->client->shouldReceive('restfulRequest') 69 | ->once() 70 | ->withArgs($args) 71 | ->andReturn($return); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/Infusionsoft/TokenTest.php: -------------------------------------------------------------------------------- 1 | '', 'refresh_token' => '', 'expires_in' => 5)); 13 | $this->assertFalse($token->isExpired()); 14 | 15 | $token = new Token(array( 'access_token' => '', 'refresh_token' => '', 'expires_in' => -5)); 16 | $this->assertTrue($token->isExpired()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 |