diff --git a/autoload.php.dist b/autoload.php.dist index 293f4e4..15bf2e7 100644 --- a/autoload.php.dist +++ b/autoload.php.dist @@ -1,5 +1,7 @@ =5.3.3" + }, + "require-dev" : { + "phpunit/phpunit": "3.7.*" + }, + "autoload" : { + "psr-0": { + "Bronto_" : "src/", + "Bronto_Tests_": "tests/" + } + }, + "minimum-stability": "stable" +} diff --git a/src/Bronto/Api.php b/src/Bronto/Api.php index a777475..0ad4c7f 100644 --- a/src/Bronto/Api.php +++ b/src/Bronto/Api.php @@ -37,6 +37,7 @@ class Bronto_Api 'type' => null, 'path' => null, ), + 'observer' => false, // SoapClient 'soap_version' => SOAP_1_1, 'compression' => true, @@ -76,6 +77,11 @@ class Bronto_Api */ protected $_uuid; + /** + * @var Bronto_Observer + */ + protected $_observer; + /** * @param string $token * @param array $options @@ -116,11 +122,20 @@ public function login() // Get a new SoapClient $this->reset(); $client = $this->getSoapClient(false); - $sessionId = $client->login(array('apiToken' => $token))->return; - $client->__setSoapHeaders(array( - new SoapHeader(self::BASE_URL, 'sessionHeader', array('sessionId' => $sessionId)) - )); - $this->_authenticated = true; + // Allow observer to inject a session before login + if ($this->getObserver()) { + $this->getObserver()->onBeforeLogin($this); + } + // Check for auth changes + if (!$this->isAuthenticated()) { + $sessionId = $client->login(array('apiToken' => $token))->return; + $this->setSessionId($sessionId); + + // Allow observer to store session + if ($this->getObserver()) { + $this->getObserver()->onAfterLogin($this, $sessionId); + } + } } catch (Exception $e) { $this->throwException($e); } @@ -128,6 +143,22 @@ public function login() return $this; } + /** + * Resuse an existing session, if possible + * + * @param string $sessionId + * @return Bronto_Api + */ + public function setSessionId($sessionId) + { + $client = $this->getSoapClient(false); + $client->__setSoapHeaders(array( + new SoapHeader(self::BASE_URL, 'sessionHeader', array('sessionId' => $sessionId)) + )); + $this->_authenticated = true; + return $this; + } + /** * We want all Exceptions to be Bronto_Api_Exception for request/response * @@ -162,6 +193,11 @@ public function throwException($exception, $message = null, $code = null) $exception->setResponse($this->getLastResponse()); } + // Allow observer to handle exception cases + if ($this->getObserver()) { + $this->getObserver()->onError($this, $exception); + } + throw $exception; } @@ -504,6 +540,13 @@ public function getRetryer(array $options = array()) if (!($this->_retryer instanceOf Bronto_Util_Retryer_RetryerInterface)) { $options = array_merge($this->_options['retryer'], $options); switch ($options['type']) { + case 'custom': + if ($options['object']) { + $this->_retryer = $options['object']; + } else { + $this->_retryer = new $options['path']; + } + break; case 'file': $this->_retryer = new Bronto_Util_Retryer_FileRetryer($options); break; @@ -516,6 +559,27 @@ public function getRetryer(array $options = array()) return $this->_retryer; } + /** + * Gets the observer for the API client + * + * @return Bronto_Observer + */ + public function getObserver() + { + if (!$this->_observer) { + if (isset($this->_options['observer'])) { + $observer = $this->_options['observer']; + if (is_string($observer) && class_exists($observer)) { + $observer = new $observer(); + } + if ($observer instanceOf Bronto_Observer) { + $this->_observer = $observer; + } + } + } + return $this->_observer; + } + /** * @return Bronto_Util_Retryer_RetryerInterface */ diff --git a/src/Bronto/Api/Object.php b/src/Bronto/Api/Object.php index 7f505db..615beaa 100644 --- a/src/Bronto/Api/Object.php +++ b/src/Bronto/Api/Object.php @@ -350,7 +350,7 @@ public function doRequest($method, array $data, $canUseRetryer = false) return $this->getApi()->throwException($exception); } else { // Attempt to get a new session token - sleep(5); + // sleep(5); $this->getApi()->login(); // If using readDirection, we have to start over if (isset($data['filter']['readDirection'])) { diff --git a/src/Bronto/Api/Order/Row.php b/src/Bronto/Api/Order/Row.php index 22c303b..8c05003 100644 --- a/src/Bronto/Api/Order/Row.php +++ b/src/Bronto/Api/Order/Row.php @@ -22,6 +22,7 @@ */ class Bronto_Api_Order_Row extends Bronto_Api_Row { + /** * @param bool $upsert Ignored * @param bool $refresh @@ -69,6 +70,8 @@ public function __set($columnName, $value) */ public function addProduct(array $data = array()) { + $products = is_null($this->products) ? array() : $this->products; + $product = new Bronto_Api_Order_Product($data); $productId = $product->id; @@ -76,11 +79,12 @@ public function addProduct(array $data = array()) throw new Bronto_Api_Order_Exception('Product must have a value for ID.'); } - if (isset($this->products[$productId])) { + if (isset($products[$productId])) { throw new Bronto_Api_Order_Exception("Product already exists in Order with ID: {$productId}"); } - - $this->products[$productId] = $product; + + $products[$productId] = $product; + $this->products = $products; return $product; } } diff --git a/src/Bronto/Observer.php b/src/Bronto/Observer.php new file mode 100644 index 0000000..6e6dcde --- /dev/null +++ b/src/Bronto/Observer.php @@ -0,0 +1,35 @@ + + * @copyright 2011-2014 Bronto Software, Inc. + * @license http://opensource.org/licenses/OSL-3.0 Open Software License v. 3.0 (OSL-3.0) + */ +interface Bronto_Observer +{ + /** + * Observe when the Bronto_Api is about to perform the login + * + * @param Bronto_Api $api + * @return void + */ + public function onBeforeLogin($api); + + /** + * Observe when the Bronto_Api client makes a login call + * + * @param Bronto_Api $api + * @param string $sessionId + * @return void + */ + public function onAfterLogin($api, $sessionId); + + /** + * Observe when the Bronto_Api client throws an exception + * + * @param Bronto_Api $api + * @param string $sessionId + * @return void + */ + public function onError($api, $exception); +} diff --git a/src/Bronto/SoapClient.php b/src/Bronto/SoapClient.php index ac744de..2dc7449 100644 --- a/src/Bronto/SoapClient.php +++ b/src/Bronto/SoapClient.php @@ -14,12 +14,13 @@ class Bronto_SoapClient extends SoapClient */ public function __doRequest($request, $location, $action, $version, $one_way = 0) { $result = parent::__doRequest($request, $location, $action, $version); - + // Only replace unicode characters if PCRE version is less than 8.30 - if (version_compare(strstr(constant('PCRE_VERSION'), ' ', true), '8.30', '<')) { + $parts = explode(' ', constant('PCRE_VERSION')); + $version = reset($parts); + if (version_compare($version, '8.30', '<')) { $result = preg_replace('/[\x{0}-\x{8}\x{B}-\x{C}\x{E}-\x{1F}\x{D800}-\x{DFFF}]/u', '', $result); } - return $result; } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index fd2535e..a732331 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -3,7 +3,9 @@ * @copyright 2011-2013 Bronto Software, Inc. * @license http://opensource.org/licenses/OSL-3.0 Open Software License v. 3.0 (OSL-3.0) */ -if (file_exists($file = __DIR__.'/../autoload.php')) { +if (file_exists($file = __DIR__.'/../vendor/autoload.php')) { + require_once $file; +} elseif (file_exists($file = __DIR__.'/../autoload.php')) { require_once $file; } elseif (file_exists($file = __DIR__.'/../autoload.php.dist')) { require_once $file;