├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit-lts.phar ├── src ├── WSClient.php └── WSClientError.php ├── tests ├── WSClientTest.php ├── bootstrap.php └── mock │ ├── body-request-login.txt │ ├── body-response-challenge.txt │ ├── body-response-login.txt │ └── response-availablemodules.txt └── travisci-phpunit.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE & System Related Files # 2 | .buildpath 3 | .project 4 | .settings 5 | .DS_Store 6 | .idea 7 | 8 | # Test Related Files # 9 | phpunit-lts.phar 10 | 11 | # Composer 12 | composer.lock 13 | composer.phar 14 | /vendor 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - "5.5" 5 | - "5.4" 6 | 7 | before_script: 8 | - composer install 9 | 10 | script: 11 | - phpunit --configuration travisci-phpunit.xml -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Valentin Despa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) 2 | 3 | Vtiger Web Services PHP Client Library (vtwsphpclib) 4 | ====================================== 5 | Composer based Vtiger Web Services Client. 6 | 7 | Build Status 8 | --------------------- 9 | Travis-CI: [![Build Status](https://travis-ci.org/vdespa/Vtiger-Web-Services-PHP-Client-Library.svg?branch=master)](https://travis-ci.org/vdespa/Vtiger-Web-Services-PHP-Client-Library) 10 | 11 | # Installation 12 | 13 | The recommended way to install vtwsphpclib is with [Composer](https://getcomposer.org/). Composer is a dependency management tool for PHP. 14 | 15 | Specify vtwsphpclib as a dependency in your **composer.json** file: 16 | 17 | { 18 | "require": { 19 | "vdespa/vtiger": "0.1" 20 | } 21 | } 22 | 23 | In case you are new to Composer, you need to include the file `/vendor/autoload.php` file. 24 | 25 | # Usage 26 | 27 | ## Creating the WSClient object 28 | use Vdespa\Vtiger\WSClient; 29 | 30 | $url = 'http://example.com/'; 31 | 32 | $config = [ 33 | 'auth' => [ 34 | 'username' => 'YOURVTIGERUSERNAME', 35 | 'accesskey' => 'YOURVTIGERACCESSKEY' 36 | ] 37 | ]; 38 | 39 | $wsclient = new WSClient($url, $config); 40 | 41 | ## Retrieving Errors 42 | 43 | If an operation fails, the return value will be false. No error will be displayed unless you call 44 | 45 | echo $wsclient->getLastError(); 46 | 47 | ## Create Object 48 | 49 | $create = $wsclient->createObject('Accounts', array('accountname' => 'Test account')); 50 | 51 | ## List Types 52 | 53 | Get a list of Vtiger objects that are available when using the API. 54 | 55 | $availableModules = $wsclient->getAvailableModules(); 56 | 57 | ## Other operations 58 | 59 | -- Work in progress -- 60 | 61 | # License 62 | 63 | Licensed using the MIT license. See LICENSE. 64 | 65 | # Thanks 66 | - Build with Guzzle 4.* 67 | - Inspired by vtwsclib – vtiger CRM Web Services Client Library version 1.4 68 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vdespa/vtiger", 3 | "type": "library", 4 | "description": "Vtiger Web Services PHP Client Library", 5 | "keywords": ["vtiger", "webservices", "vtwsclib"], 6 | "homepage": "https://github.com/vdespa/Vtiger-Web-Services-PHP-Client-Library", 7 | "license": "The MIT License (MIT)", 8 | "require": { 9 | "php": ">=5.4", 10 | "guzzlehttp/guzzle": "4.*" 11 | }, 12 | "autoload": { 13 | "psr-4": { 14 | "Vdespa\\Vtiger\\": "src/", 15 | "Vdespa\\Vtiger\\Tests\\": "Tests/" 16 | } 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /phpunit-lts.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vdespa/Vtiger-Web-Services-PHP-Client-Library/d835071eb358e6795c360ff9d54d5b2f5fdf1155/phpunit-lts.phar -------------------------------------------------------------------------------- /src/WSClient.php: -------------------------------------------------------------------------------- 1 | . All rights reserved. 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | * 30 | * @author Valentin Despa 31 | * @copyright 2014 Valentin Despa 32 | * @license The MIT License (MIT) 33 | */ 34 | 35 | namespace Vdespa\Vtiger; 36 | 37 | use GuzzleHttp\Client; 38 | use GuzzleHttp\Exception\RequestException; 39 | 40 | /** 41 | * Vtiger Web Services Client. 42 | * 43 | * Class WSClient 44 | * @package Vdespa\Vtiger 45 | */ 46 | class WSClient 47 | { 48 | /** 49 | * Default PHP script for web services on Vtiger installation 50 | * 51 | * @var string 52 | */ 53 | protected $wsFileName = 'webservice.php'; 54 | 55 | /** 56 | * Complete URL 57 | * 58 | * @var string 59 | */ 60 | protected $vtigerWebServiceURL; 61 | 62 | /** 63 | * HTTP Client 64 | * 65 | * @var \GuzzleHttp\Client 66 | */ 67 | protected $httpClient; 68 | 69 | /** 70 | * Session name 71 | * 72 | * @var string 73 | */ 74 | protected $sessionName; 75 | 76 | /** 77 | * User Id 78 | * 79 | * @var string 80 | */ 81 | protected $userId; 82 | 83 | /** 84 | * Web Service Version 85 | * 86 | * @var string 87 | */ 88 | protected $apiVersion; 89 | 90 | /** 91 | * Vtiger version 92 | * 93 | * @var string 94 | */ 95 | protected $vtigerVersion; 96 | 97 | /** 98 | * Last error 99 | * 100 | * @var WSClientError 101 | */ 102 | protected $lastError; 103 | 104 | /** 105 | * Constructor. 106 | * 107 | * todo $url should be packed in the config. 108 | */ 109 | public function __construct($url, $config = array()) 110 | { 111 | // Build the URL 112 | $this->vtigerWebServiceURL = $this->buildWebServiceURL($url, $config); 113 | 114 | // Create HTTP client 115 | if (array_key_exists('testing', $config) && array_key_exists('client', $config['testing']) && $config['testing']['client'] instanceof Client) 116 | { 117 | $this->httpClient = $config['testing']['client']; 118 | } 119 | else 120 | { 121 | $this->httpClient = new Client(); 122 | } 123 | 124 | 125 | // Login 126 | if (array_key_exists('username', $config['auth']) && array_key_exists('accesskey', $config['auth'])) 127 | { 128 | $login = $this->login($config['auth']['username'], $config['auth']['accesskey']); 129 | } 130 | else 131 | { 132 | $this->lastError = new WSClientError( 133 | 'NO_CREDENTIALS_FOUND', 134 | 'Username or accesskey not provided.', 135 | var_export($config) 136 | ); 137 | } 138 | } 139 | 140 | /** 141 | * Build the URL based on the base url and the config. 142 | * 143 | * @param string $url 144 | * @param array $config 145 | * @return string 146 | */ 147 | protected function buildWebServiceURL($url, array $config) 148 | { 149 | // Check if URL already contains 'webservice.php' 150 | if(stripos($url, $this->wsFileName) === false) 151 | { 152 | // If the URL does not end with a slash, add one. 153 | if(strripos($url, '/') != (strlen($url)-1)) 154 | { 155 | $url .= '/'; 156 | } 157 | $url .= $this->wsFileName; 158 | } 159 | 160 | // Add additional parameters to the request 161 | if (array_key_exists('query-params', $config) && ! empty($config['query-params'])) 162 | { 163 | $url .= "?" . http_build_query($config['query-params']); 164 | } 165 | 166 | return $url; 167 | } 168 | 169 | /** 170 | * Perform Login Operation. 171 | * 172 | * @param string $username 173 | * @param string $accessKey 174 | * @return bool 175 | */ 176 | protected function login($username, $accessKey) { 177 | 178 | $challenge = $this->getChallenge($username); 179 | 180 | if ($challenge !== false) 181 | { 182 | $response = $this->httpClient->post($this->vtigerWebServiceURL, [ 183 | 'body' => [ 184 | 'operation' => 'login', 185 | 'username' => $username, 186 | 'accessKey' => md5($challenge . $accessKey) 187 | ] 188 | ]); 189 | 190 | $json = $response->json(); 191 | 192 | if ($json['success'] === true) 193 | { 194 | $this->sessionName = $json['result']['sessionName']; 195 | $this->userId = $json['result']['userId']; 196 | $this->apiVersion = $json['result']['version']; 197 | $this->vtigerVersion = $json['result']['vtigerVersion']; 198 | return true; 199 | } 200 | else 201 | { 202 | $this->lastError = new WSClientError( 203 | $json['error']['code'], 204 | $json['error']['message'], 205 | $json['error']['xdebug_message'] 206 | ); 207 | return false; 208 | } 209 | } 210 | else 211 | { 212 | return false; 213 | } 214 | } 215 | 216 | /** 217 | * Close current session 218 | * 219 | * @return bool 220 | */ 221 | public function logout() 222 | { 223 | $response = $this->httpClient->get($this->vtigerWebServiceURL, [ 224 | 'query' => [ 225 | 'operation' => 'logout', 226 | 'sessionName' => $this->sessionName 227 | ] 228 | ]); 229 | 230 | $json = $response->json(); 231 | 232 | if ($json['success'] === true) 233 | { 234 | return true; 235 | } 236 | else 237 | { 238 | $this->lastError = new WSClientError( 239 | $json['error']['code'], 240 | $json['error']['message'], 241 | $json['error']['xdebug_message'] 242 | ); 243 | return false; 244 | } 245 | } 246 | 247 | /** 248 | * Get a challenge token from the server 249 | * 250 | * @param string $username 251 | * @return string | bool 252 | */ 253 | protected function getChallenge($username) 254 | { 255 | try 256 | { 257 | $response = $this->httpClient->get($this->vtigerWebServiceURL, [ 258 | 'query' => [ 259 | 'operation' => 'getchallenge', 260 | 'username' => $username 261 | ] 262 | ]); 263 | } 264 | catch (RequestException $e) 265 | { 266 | $this->lastError = new WSClientError( 267 | $e->getCode(), 268 | $e->getMessage(), 269 | null 270 | ); 271 | return false; 272 | } 273 | 274 | $json = $response->json(); 275 | 276 | if ($json['success'] === true) 277 | { 278 | return $json['result']['token']; 279 | } 280 | else 281 | { 282 | $this->lastError = new WSClientError( 283 | $json['error']['code'], 284 | $json['error']['message'], 285 | $json['error']['xdebug_message'] 286 | ); 287 | return false; 288 | } 289 | } 290 | 291 | /** 292 | * Provides a list of available modules. 293 | * 294 | * This list only contains modules the logged in user has access to. 295 | * 296 | * @return array | bool 297 | */ 298 | public function getAvailableModules() 299 | { 300 | $response = $this->httpClient->get($this->vtigerWebServiceURL, [ 301 | 'query' => [ 302 | 'operation' => 'listtypes', 303 | 'sessionName' => $this->sessionName 304 | ] 305 | ]); 306 | 307 | $json = $response->json(); 308 | 309 | if ($json['success'] === true) 310 | { 311 | return $json['result']['types']; 312 | } 313 | else 314 | { 315 | $this->lastError = new WSClientError( 316 | $json['error']['code'], 317 | $json['error']['message'], 318 | $json['error']['xdebug_message'] 319 | ); 320 | return false; 321 | } 322 | } 323 | 324 | /** 325 | * Describes a Vtiger module 326 | * 327 | * @param $moduleName 328 | * @return array | bool 329 | */ 330 | public function getModuleDescription($moduleName) 331 | { 332 | $response = $this->httpClient->get($this->vtigerWebServiceURL, [ 333 | 'query' => [ 334 | 'operation' => 'describe', 335 | 'sessionName' => $this->sessionName, 336 | 'elementType' => $moduleName 337 | ] 338 | ]); 339 | 340 | $json = $response->json(); 341 | 342 | if ($json['success'] === true) 343 | { 344 | return $json['result']; 345 | } 346 | else 347 | { 348 | $this->lastError = new WSClientError( 349 | $json['error']['code'], 350 | $json['error']['message'], 351 | $json['error']['xdebug_message'] 352 | ); 353 | return false; 354 | } 355 | } 356 | 357 | /** 358 | * Create a new object 359 | * 360 | * @param $moduleName 361 | * @param array $data 362 | * @return bool 363 | */ 364 | public function createObject($moduleName, array $data) 365 | { 366 | // Use current user if no user is specified 367 | if(! array_key_exists('assigned_user_id', $data)) 368 | { 369 | $data['assigned_user_id'] = $this->userId; 370 | } 371 | 372 | // Encode as JSON 373 | $element = json_encode($data); 374 | 375 | $response = $this->httpClient->post($this->vtigerWebServiceURL, [ 376 | 'body' => [ 377 | 'operation' => 'create', 378 | 'sessionName' => $this->sessionName, 379 | 'elementType' => $moduleName, 380 | 'element' => $element 381 | ] 382 | ]); 383 | 384 | $json = $response->json(); 385 | 386 | if ($json['success'] === true) 387 | { 388 | return $json['result']; 389 | } 390 | else 391 | { 392 | $this->lastError = new WSClientError( 393 | $json['error']['code'], 394 | $json['error']['message'], 395 | $json['error']['xdebug_message'] 396 | ); 397 | return false; 398 | } 399 | } 400 | 401 | /** 402 | * Retrieve existing object 403 | * 404 | * @param $recordId 405 | * @return bool 406 | */ 407 | public function retrieveObject($recordId) 408 | { 409 | $response = $this->httpClient->get($this->vtigerWebServiceURL, [ 410 | 'query' => [ 411 | 'operation' => 'retrieve', 412 | 'sessionName' => $this->sessionName, 413 | 'id' => $recordId 414 | ] 415 | ]); 416 | 417 | $json = $response->json(); 418 | 419 | if ($json['success'] === true) 420 | { 421 | return $json['result']; 422 | } 423 | else 424 | { 425 | $this->lastError = new WSClientError( 426 | $json['error']['code'], 427 | $json['error']['message'], 428 | $json['error']['xdebug_message'] 429 | ); 430 | return false; 431 | } 432 | } 433 | 434 | /** 435 | * Update object 436 | * 437 | * It will first retrieve the object from the database and merge the new information 438 | * 439 | * @param array $data 440 | * @return bool 441 | */ 442 | public function updateObject(array $data) 443 | { 444 | // Retrieve data 445 | $initialObject = $this->retrieveObject($data['id']); 446 | 447 | if ($initialObject !== false) 448 | { 449 | // Merge old and new data 450 | $updatedObject = array_merge($initialObject, $data); 451 | 452 | // Encode as JSON 453 | $element = json_encode($updatedObject); 454 | 455 | $response = $this->httpClient->post($this->vtigerWebServiceURL, [ 456 | 'body' => [ 457 | 'operation' => 'update', 458 | 'sessionName' => $this->sessionName, 459 | 'element' => $element 460 | ] 461 | ]); 462 | 463 | $json = $response->json(); 464 | 465 | if ($json['success'] === true) 466 | { 467 | return $json['result']; 468 | } 469 | else 470 | { 471 | $this->lastError = new WSClientError( 472 | $json['error']['code'], 473 | $json['error']['message'], 474 | $json['error']['xdebug_message'] 475 | ); 476 | return false; 477 | } 478 | } 479 | else 480 | { 481 | return false; 482 | } 483 | } 484 | 485 | /** 486 | * Delete object 487 | * 488 | * @param $recordId 489 | * @return bool 490 | */ 491 | public function deleteObject($recordId) 492 | { 493 | $response = $this->httpClient->post($this->vtigerWebServiceURL, [ 494 | 'body' => [ 495 | 'operation' => 'delete', 496 | 'sessionName' => $this->sessionName, 497 | 'id' => $recordId 498 | ] 499 | ]); 500 | 501 | $json = $response->json(); 502 | 503 | if ($json['success'] === true) 504 | { 505 | return $json['result']; 506 | } 507 | else 508 | { 509 | $this->lastError = new WSClientError( 510 | $json['error']['code'], 511 | $json['error']['message'], 512 | $json['error']['xdebug_message'] 513 | ); 514 | return false; 515 | } 516 | } 517 | 518 | /** 519 | * Simple query mechanism 520 | * 521 | * @param $query 522 | * @return bool 523 | */ 524 | public function query($query) 525 | { 526 | $response = $this->httpClient->get($this->vtigerWebServiceURL, [ 527 | 'query' => [ 528 | 'operation' => 'query', 529 | 'sessionName' => $this->sessionName, 530 | 'query' => $query 531 | ] 532 | ]); 533 | 534 | $json = $response->json(); 535 | 536 | if ($json['success'] === true) 537 | { 538 | return $json['result']; 539 | } 540 | else 541 | { 542 | $this->lastError = new WSClientError( 543 | $json['error']['code'], 544 | $json['error']['message'], 545 | $json['error']['xdebug_message'] 546 | ); 547 | return false; 548 | } 549 | } 550 | 551 | /** 552 | * Sync will return a SyncResult object containing details of changes after modifiedTime. 553 | * 554 | * @param string $moduleName 555 | * @param int $modifiedTime 556 | * @return array | bool 557 | */ 558 | public function sync($moduleName, $modifiedTime) 559 | { 560 | $response = $this->httpClient->get($this->vtigerWebServiceURL, [ 561 | 'query' => [ 562 | 'operation' => 'sync', 563 | 'sessionName' => $this->sessionName, 564 | 'modifiedTime' => (int) $modifiedTime, 565 | 'elementType' => $moduleName 566 | ] 567 | ]); 568 | 569 | $json = $response->json(); 570 | 571 | if ($json['success'] === true) 572 | { 573 | return $json['result']; 574 | } 575 | else 576 | { 577 | $this->lastError = new WSClientError( 578 | $json['error']['code'], 579 | $json['error']['message'], 580 | $json['error']['xdebug_message'] 581 | ); 582 | return false; 583 | } 584 | } 585 | 586 | /** 587 | * Invoke custom operation 588 | * 589 | * @param string $operation Name of the operation to invoke 590 | * @param array $params 591 | * @param string $httpMethod HTTP method to use 592 | * @return bool 593 | */ 594 | function callOperation($operation, array $params, $httpMethod = 'POST') 595 | { 596 | $data = array( 597 | 'operation' => $operation, 598 | 'sessionName' => $this->sessionName 599 | ); 600 | 601 | $data = array_merge($data, $params); 602 | 603 | try 604 | { 605 | if ($httpMethod === 'GET') 606 | { 607 | $response = $this->httpClient->get($this->vtigerWebServiceURL, [ 608 | 'query' => $data 609 | ]); 610 | } 611 | 612 | if ($httpMethod === 'POST') 613 | { 614 | $response = $this->httpClient->post($this->vtigerWebServiceURL, [ 615 | 'body' => $data 616 | ]); 617 | } 618 | } 619 | catch (RequestException $e) 620 | { 621 | $this->lastError = new WSClientError( 622 | $e->getCode(), 623 | $e->getMessage(), 624 | null 625 | ); 626 | return false; 627 | } 628 | 629 | 630 | $json = $response->json(); 631 | 632 | if ($json['success'] === true) 633 | { 634 | return $json['result']; 635 | } 636 | else 637 | { 638 | $this->lastError = new WSClientError( 639 | $json['error']['code'], 640 | $json['error']['message'], 641 | $json['error']['xdebug_message'] 642 | ); 643 | return false; 644 | } 645 | } 646 | 647 | /** 648 | * Get last error 649 | * 650 | * @return WSClientError 651 | */ 652 | public function getLastError() 653 | { 654 | return $this->lastError; 655 | } 656 | 657 | /** 658 | * Return an instance of the http client 659 | * 660 | * @return \GuzzleHttp\Client 661 | */ 662 | public function getHttpClient() 663 | { 664 | return $this->httpClient; 665 | } 666 | } -------------------------------------------------------------------------------- /src/WSClientError.php: -------------------------------------------------------------------------------- 1 | . All rights reserved. 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | * @author Valentin Despa 32 | * @copyright 2014 Valentin Despa 33 | * @license The MIT License (MIT) 34 | */ 35 | 36 | namespace Vdespa\Vtiger; 37 | 38 | /** 39 | * Class WSClientError 40 | * 41 | * @package Vdespa\Vtiger 42 | */ 43 | class WSClientError 44 | { 45 | protected $errorCode; 46 | 47 | /** 48 | * @return mixed 49 | */ 50 | public function getErrorCode() 51 | { 52 | return $this->errorCode; 53 | } 54 | 55 | /** 56 | * @return mixed 57 | */ 58 | public function getMessage() 59 | { 60 | return $this->message; 61 | } 62 | protected $message; 63 | protected $xdebugMessage; 64 | 65 | /** 66 | * Constructor 67 | * 68 | * @param $code 69 | * @param $message 70 | * @param $xdebugMessage 71 | */ 72 | public function __construct($code, $message, $xdebugMessage) 73 | { 74 | $this->errorCode = $code; 75 | $this->message = $message; 76 | $this->xdebugMessage = $xdebugMessage; 77 | } 78 | 79 | /** 80 | * @return string 81 | */ 82 | public function __toString() 83 | { 84 | return 'Error code: ' . $this->errorCode . '. Message: ' . $this->message; 85 | } 86 | 87 | /** 88 | * @return mixed 89 | */ 90 | public function getDebugMessage() 91 | { 92 | return $this->xdebugMessage; 93 | } 94 | } -------------------------------------------------------------------------------- /tests/WSClientTest.php: -------------------------------------------------------------------------------- 1 | . All rights reserved. 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | * @author Valentin Despa 32 | * @copyright 2014 Valentin Despa 33 | * @license The MIT License (MIT) 34 | */ 35 | 36 | use Vdespa\Vtiger\WSClient; 37 | 38 | use GuzzleHttp\Client; 39 | use GuzzleHttp\Message\Response; 40 | use GuzzleHttp\Subscriber\Mock; 41 | use GuzzleHttp\Subscriber\History; 42 | use GuzzleHttp\Stream\Stream; 43 | 44 | 45 | class WSClientTest extends \PHPUnit_Framework_TestCase 46 | { 47 | /** 48 | * @var Client 49 | */ 50 | protected $client; 51 | 52 | /** 53 | * @var WSClient 54 | */ 55 | protected $wsclient; 56 | 57 | /** 58 | * @var History 59 | */ 60 | protected $history; 61 | 62 | protected function setUp() 63 | { 64 | // Create a history subscriber 65 | $this->history = new History(); 66 | 67 | // Create the client 68 | $this->client = new Client; 69 | 70 | // Add the history subscriber to the client. 71 | $this->client->getEmitter()->attach($this->history); 72 | 73 | $this->authentication(); 74 | } 75 | 76 | protected function authentication() 77 | { 78 | // Setting for the WSClient 79 | $url = 'http://www.example.com'; 80 | $config = [ 81 | 'auth' => [ 82 | 'username' => 'system', 83 | 'accesskey' => 'TkDShdBqAnav2EhG' 84 | ], 85 | // Providing the Guzzle client in test so we can easily use history and mock responses 86 | 'testing' => [ 87 | 'client' => $this->client 88 | ] 89 | ]; 90 | 91 | $mock = new Mock([ 92 | // Use response object 93 | new Response(200, [], Stream::factory(fopen('./tests/mock/body-response-challenge.txt', 'r+'))), 94 | new Response(200, [], Stream::factory(fopen('./tests/mock/body-response-login.txt', 'r+'))), 95 | ]); 96 | $this->client->getEmitter()->attach($mock); 97 | 98 | // Create the WSClient 99 | $this->wsclient = new WSClient($url, $config); 100 | 101 | $requests = $this->history->getRequests(); 102 | 103 | // Operation getchallenge 104 | $this->assertEquals( 105 | 'http://www.example.com/webservice.php?operation=getchallenge&username=system', 106 | $requests[0]->getUrl() 107 | ); 108 | $this->assertEquals('GET', $requests[0]->getMethod()); 109 | 110 | // Operation login 111 | $this->assertEquals( 112 | 'http://www.example.com/webservice.php', 113 | $requests[1]->getUrl() 114 | ); 115 | $this->assertEquals('POST', $requests[1]->getMethod()); 116 | $this->assertEquals( 117 | 'operation=login&username=system&accessKey=452e4d2f10d60e481c2056ef2e12ed48', 118 | (string) $requests[1]->getBody() 119 | ); 120 | 121 | // Detaching subscriber 122 | $this->client->getEmitter()->detach($mock); 123 | } 124 | 125 | public function testCanCreateClient() 126 | { 127 | $this->assertInstanceOf('\GuzzleHttp\Client', $this->client); 128 | } 129 | 130 | public function testCanCreateWSClient() 131 | { 132 | $this->assertInstanceOf('\Vdespa\Vtiger\WSClient', $this->wsclient); 133 | } 134 | 135 | public function testCanGetAvailableModules() 136 | { 137 | // Create a mock subscriber and queue the response. 138 | $mock = new Mock([ 139 | new Response(file_get_contents('./tests/mock/response-availablemodules.txt')) 140 | ]); 141 | $this->client->getEmitter()->attach($mock); 142 | 143 | // Get available modules 144 | $this->wsclient->getAvailableModules(); 145 | 146 | // Get the last request 147 | $lastRequest = $this->history->getLastRequest(); 148 | 149 | $this->assertEquals( 150 | 'http://www.example.com/webservice.php?operation=listtypes&sessionName=18653fb863106084', 151 | $lastRequest->getUrl() 152 | ); 153 | $this->assertEquals('GET', $lastRequest->getMethod()); 154 | $this->assertEmpty((string) $lastRequest->getBody()); 155 | 156 | // Detaching subscriber 157 | $this->client->getEmitter()->detach($mock); 158 | } 159 | } -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./tests/ 6 | 7 | 8 | 9 | 10 | 11 | ./ 12 | 13 | ./tests 14 | 15 | 16 | 17 | --------------------------------------------------------------------------------