public function LogPlatformRequests($xml, $url, $headers, $isRequest)
    {
        if ($this->EnableServiceRequestsLogging) {
            if (false === file_exists($this->ServiceRequestLoggingLocation)) {
                $this->ServiceRequestLoggingLocation = sys_get_temp_dir();
            }

            // Use filecount to have some sort of sequence number for debugging purposes - 5 digits
                  $sequenceNumber = iterator_count(new \DirectoryIterator($this->ServiceRequestLoggingLocation));
            $sequenceNumber = str_pad((int)$sequenceNumber, 5, "0", STR_PAD_LEFT);

            $iter = 0;
            $filePath = null;
            do {
                $filePath = null;
                if ($isRequest) {
                    $filePath = CoreConstants::REQUESTFILENAME_FORMAT;
                    $filePath = str_replace("{0}", $this->ServiceRequestLoggingLocation, $filePath);
                } else {
                    $filePath = CoreConstants::RESPONSEFILENAME_FORMAT;
                    $filePath = str_replace("{0}", $this->ServiceRequestLoggingLocation, $filePath);
                }
                $filePath = str_replace("{1}", CoreConstants::SLASH_CHAR.$sequenceNumber.'-', $filePath);
                $filePath = str_replace("{2}", time()."-".(int)$iter, $filePath);
                $iter++;
            } while (file_exists($filePath));

            try {
                $collapsedHeaders = array();
                foreach ($headers as $key=>$val) {
                    $collapsedHeaders[] = "{$key}: {$val}";
                }

                file_put_contents($filePath,
                                  ($isRequest?"REQUEST":"RESPONSE")." URI FOR SEQUENCE ID {$sequenceNumber}\n==================================\n{$url}\n\n",
                                  FILE_APPEND);
                file_put_contents($filePath,
                                  ($isRequest?"REQUEST":"RESPONSE")." HEADERS\n================\n".implode("\n", $collapsedHeaders)."\n\n",
                                  FILE_APPEND);
                file_put_contents($filePath,
                                  ($isRequest?"REQUEST":"RESPONSE")." BODY\n=============\n".$xml."\n\n",
                                  FILE_APPEND);
            } catch (\Exception $e) {
                throw new IdsException("Exception during LogPlatformRequests.");
            }
        }
    }

Logs the Platform Request to Disk.
@param string xml The xml to log.
@param string url of the request/response
@param array headers HTTP headers of the request/response
@param bool isRequest Specifies whether the xml is request or response.


public function isAllowed($entity, $operation)
    {
        //fallback to global rules if entity wasn't specified in the rules
        $lookupEn = array_key_exists($entity, $this->operationList)
                            ? $entity
                            : self::ALL;

        //fallback to global rules if operation wasn't specified in the rules
        $lookupOp = array_key_exists($operation, $this->operationList[$lookupEn])
                            ? $operation
                            : self::ALL;

        // entity and operation were found as is
        if (($entity === $lookupEn) && ($operation === $lookupOp)) {
            return $this->operationList[$lookupEn][$lookupOp];
        }

        //lookup for operation for current entity if it exists
        if (array_key_exists($lookupOp, $this->operationList[$lookupEn])) {
            return $this->operationList[$lookupEn][$lookupOp];
        }

        //lookup for operation for current entity if it exists
        if (array_key_exists($operation, $this->operationList[self::ALL])) {
            return $this->operationList[self::ALL][$operation];
        }

        //fallback to global entity
        if (array_key_exists($lookupOp, $this->operationList[self::ALL])) {
            return $this->operationList[self::ALL][$lookupOp];
        }

        //fall back to global entity and operation
        return $this->operationList[self::ALL][self::ALL];
    }

Verifies if operation is available for some entity
@param string $entity
@param string $operation
@return bool


private function prepareReflection()
    {
        $methods = $this->getClassMethods();
        foreach ($methods as $method) {
            $this->methodsMeta[$method->name] = $this->getMethodIO($method->name);
        }
    }

private function prepareReflection ( ) { $ methods = $ this -> getClassMethods ( ) ; foreach ( $ methods as $ method ) { $ this -> methodsMeta [ $ method -> name ] = $ this -> getMethodIO ( $ method -> name ) ; } }

Prepare service class reflection

@return void


public function toXml()
    {
        if (is_string($this->wsdlXmlSource) && $this->wsdlXmlSource != '') {
            return $this->wsdlXmlSource;
        } else {
            $this->prepareDom();
            $this->prepareReflection();
            $this->prepare();
            $this->wsdlXmlSource = $this->dom->saveXML();
            return $this->wsdlXmlSource;
        }
    }

public function toXml ( ) { if ( is_string ( $ this -> wsdlXmlSource ) && $ this -> wsdlXmlSource != '' ) { return $ this -> wsdlXmlSource ; } else { $ this -> prepareDom ( ) ; $ this -> prepareReflection ( ) ; $ this -> prepare ( ) ; $ this -> wsdlXmlSource = $ this -> dom -> saveXML ( ) ; return $ this -> wsdlXmlSource ; } }

Return WSDL as XML string

@return string


public function copyToPublic($path, $overwrite = false)
    {
        $publicPath = realpath($this->getPublicPath());
        $targetFilePath   = $publicPath.DIRECTORY_SEPARATOR.basename($path);

        if (($overwrite === true && file_exists($targetFilePath)) || !file_exists($targetFilePath)) {
            if (!copy($path, $targetFilePath)) {
                throw new \RuntimeException("Cannot copy ".basename($path)." to ".$publicPath);
            }
        }

        return $targetFilePath;
    }

public
function
copyToPublic
(
$
path
,
$
overwrite
=
false
)
{
$
publicPath
=
realpath
(
$
this
->
getPublicPath
(
)
)
;
$
targetFilePath
=
$
publicPath
.
DIRECTORY_SEPARATOR
.
basename
(
$
path
)
;
if
(
(
$
overwrite
===
true
&&
file_exists
(
$
targetFilePath
)
)
||
!
file_exists
(
$
targetFilePath
)
)
{
if
(
!
copy
(
$
path
,
$
targetFilePath
)
)
{
throw
new
\
RuntimeException
(
"Cannot copy "
.
basename
(
$
path
)
.
" to "
.
$
publicPath
)
;
}
}
return
$
targetFilePath
;
}

Copy given file to publicSchemaPath

@param string  $path      Path to file
@param boolean $overwrite Overwrite file if it exists? default false

@return string Path to new file
@throws RuntimeException If file cannot be copied


private function castToStringZero($prop, $obj)
    {
        if ($this->isEmptyInt($prop->getValue($obj))) {
            //reset value in very specific case to keep it intact
            $prop->setValue($obj, (string) $prop->getValue($obj));
        }
    }

Cast numeric empty value to string
@see SDK-78
@param ReflectionProperty $prop
@param Object $obj


public static function ReadConfigurationFromFile($filePath, $OAuthOption = CoreConstants::OAUTH1)
    {
        $ippConfig = new IppConfiguration();

        try {
            if (isset($filePath) && file_exists($filePath)) {
                $xmlObj = simplexml_load_file($filePath);
            } else {
                // $xmlObj = simplexml_load_file(PATH_SDK_ROOT . 'sdk.config');
                 throw new \Exception("Can't Read Configuration from file: ". $filePath);
            }

            LocalConfigReader::initializeOAuthSettings($xmlObj, $ippConfig, $OAuthOption);
            LocalConfigReader::initializeRequestAndResponseSerializationAndCompressionFormat($xmlObj, $ippConfig);
            LocalConfigReader::intializaeServiceBaseURLAndLogger($xmlObj, $ippConfig);
            LocalConfigReader::initializeAPIEntityRules($xmlObj, $ippConfig);
            LocalConfigReader::setupMinorVersion($ippConfig, $xmlObj);

            return $ippConfig;
        } catch (\Exception $e) {
            throw new SdkException("Error Reading the ");
        }
    }

Reads the configuration from the config file and converts it to custom
config objects which the end developer will use to get or set the properties.

@param $filePath
A Customer FilePath. If different than the default sdk.config file
@return IppConfiguration The custom config object.

Reads the configuration from the config file and converts it to custom config objects which the end developer will use to get or set the properties .


public static function initializeAPIEntityRules($xmlObj, $ippConfig)
    {
        $rules=CoreConstants::getQuickBooksOnlineAPIEntityRules();
        LocalConfigReader::initOperationControlList($ippConfig, $rules);
        $specialConfig = LocalConfigReader::populateJsonOnlyEntities($xmlObj);
        if (is_array($specialConfig) && ($ippConfig->OpControlList instanceof OperationControlList)) {
            $ippConfig->OpControlList->appendRules($specialConfig);
        }
    }

public static function initializeAPIEntityRules ( $ xmlObj , $ ippConfig ) { $ rules = CoreConstants :: getQuickBooksOnlineAPIEntityRules ( ) ; LocalConfigReader :: initOperationControlList ( $ ippConfig , $ rules ) ; $ specialConfig = LocalConfigReader :: populateJsonOnlyEntities ( $ xmlObj ) ; if ( is_array ( $ specialConfig ) && ( $ ippConfig -> OpControlList instanceof OperationControlList ) ) { $ ippConfig -> OpControlList -> appendRules ( $ specialConfig ) ; } }

Initializes API Entity Rules

@param IppConfiguration $ippConfig
@param \SimpleXMLElement $xmlObj


public static function populateJsonOnlyEntities($xmlObj)
   {
       if (isset($xmlObj) &&
            isset($xmlObj->intuit->ipp->specialConfiguration)) {
           $specialCnf = $xmlObj->intuit->ipp->specialConfiguration;
           if (!$specialCnf instanceof SimpleXMLElement) {
               return false;
           }
           if (!$specialCnf->children() instanceof SimpleXMLElement) {
               return false;
           }
           if (!$specialCnf->children()->count()) {
               return false;
           }
           $rules = array();
           foreach ($specialCnf->children() as $entity) {
               if (!$entity->attributes()->count()) {
                   continue;
               }
               $name = self::decorateEntity($entity->getName());
               if (!array_key_exists($name, $rules)) {
                   $rules[$name] = array();
               }
               foreach ($entity->attributes() as $attr) {
                   $rules[$name][$attr->getName()] = filter_var((string)$entity->attributes(), FILTER_VALIDATE_BOOLEAN);
               }
           }
           return $rules;
       }
       return false;
   }

public static function populateJsonOnlyEntities ( $ xmlObj ) { if ( isset ( $ xmlObj ) && isset ( $ xmlObj -> intuit -> ipp -> specialConfiguration ) ) { $ specialCnf = $ xmlObj -> intuit -> ipp -> specialConfiguration ; if ( ! $ specialCnf instanceof SimpleXMLElement ) { return false ; } if ( ! $ specialCnf -> children ( ) instanceof SimpleXMLElement ) { return false ; } if ( ! $ specialCnf -> children ( ) -> count ( ) ) { return false ; } $ rules = array ( ) ; foreach ( $ specialCnf -> children ( ) as $ entity ) { if ( ! $ entity -> attributes ( ) -> count ( ) ) { continue ; } $ name = self :: decorateEntity ( $ entity -> getName ( ) ) ; if ( ! array_key_exists ( $ name , $ rules ) ) { $ rules [ $ name ] = array ( ) ; } foreach ( $ entity -> attributes ( ) as $ attr ) { $ rules [ $ name ] [ $ attr -> getName ( ) ] = filter_var ( ( string ) $ entity -> attributes ( ) , FILTER_VALIDATE_BOOLEAN ) ; } } return $ rules ; } return false ; }

Returns array in a OperationControlList rules format from XML
@param \SimpleXMLElement $xmlObj
@return boolean


public static function initializeOAuthSettings($xmlObj, $ippConfig, $OAuthOption)
   {

         // if it is OAuth1 Settings.
         if (isset($xmlObj) &&
                 isset($xmlObj->intuit->ipp->security) &&
                 $OAuthOption == CoreConstants::OAUTH1  &&
                 isset($xmlObj->intuit->ipp->security->oauth1)) {
             try {
                 $currentAccessTokenKey = $xmlObj->intuit->ipp->security->oauth1->attributes()['accessTokenKey'];
                 $currentAccessTokenSecret = $xmlObj->intuit->ipp->security->oauth1->attributes()['accessTokenSecret'];
                 $currentConsumerKey = $xmlObj->intuit->ipp->security->oauth1->attributes()['consumerKey'];
                 $currentConsumerSecret =    $xmlObj->intuit->ipp->security->oauth1->attributes()['consumerSecret'];
                 $ippConfig->RealmID =  $xmlObj->intuit->ipp->security->oauth1->attributes()['QBORealmID'];
                 $ippConfig->OAuthMode = CoreConstants::OAUTH1;
             } catch (\Exception $e) {
                 throw new \Exception("Can't Read OAuth1 values from config file.");
             }
             $ippConfig->Security = new OAuthRequestValidator($currentAccessTokenKey, $currentAccessTokenSecret, $currentConsumerKey, $currentConsumerSecret);
         }
         // OAUth 2 settings if available
         elseif (isset($xmlObj) &&
                 isset($xmlObj->intuit->ipp->security) &&
                 $OAuthOption == CoreConstants::OAUTH2  &&
                 isset($xmlObj->intuit->ipp->security->oauth2)) {
             //Implement OAuth 2 parts here
            // Set SSL check status to be true
            $ippConfig->SSLCheckStatus = true;
            $currentOAuth2AccessTokenKey = $xmlObj->intuit->ipp->security->oauth2->attributes()['accessTokenKey'];
            $currentOAuth2RefreshTokenKey = $xmlObj->intuit->ipp->security->oauth2->attributes()['refreshTokenKey'];
            $clientID = $xmlObj->intuit->ipp->security->oauth2->attributes()['ClientID'];
            $clientSecret =    $xmlObj->intuit->ipp->security->oauth2->attributes()['ClientSecret'];
            $ippConfig->RealmID =  $xmlObj->intuit->ipp->security->oauth2->attributes()['QBORealmID'];
            $OAuth2AccessToken = new OAuth2AccessToken($clientID, $clientSecret, $currentOAuth2AccessTokenKey, $currentOAuth2RefreshTokenKey);

            $ippConfig->Security = $OAuth2AccessToken;
            $ippConfig->OAuthMode = CoreConstants::OAUTH2;
         } else {
             throw new \Exception("Can't load " .$OAuthOption .  " config from config file or the OAuth option is not supported.");
         }
   }

Initialize OAuth Settings from Simple XML Reading from SDK.config or specific file
rightnow the default OAuth module is OAuth 1.
@Hao

Initialize OAuth Settings from Simple XML Reading from SDK . config or specific file rightnow the default OAuth module is OAuth 1 .


public static function initializeRequestAndResponseSerializationAndCompressionFormat($xmlObj, $ippConfig)
     {
         LocalConfigReader::intializeMessage($ippConfig);

         $requestSerializationFormat = null;
         $requestCompressionFormat = null;
         $responseSerializationFormat = null;
         $responseCompressionFormat = null;

         if (isset($xmlObj) &&
                 isset($xmlObj->intuit->ipp->message->request)) {
             $requestAttr = $xmlObj->intuit->ipp->message->request->attributes();
             $requestSerializationFormat = (string)$requestAttr->serializationFormat;
             $requestCompressionFormat = (string)$requestAttr->compressionFormat;
         }

         // Initialize Response Configuration Object
         if (isset($xmlObj) &&
                 isset($xmlObj->intuit->ipp->message->response)) {
             $responseAttr = $xmlObj->intuit->ipp->message->response->attributes();
             $responseSerializationFormat = (string)$responseAttr->serializationFormat;
             $responseCompressionFormat = (string)$responseAttr->compressionFormat;
         }
         LocalConfigReader::setRequestAndResponseSerializationFormat($ippConfig, $requestCompressionFormat, $responseCompressionFormat, $requestSerializationFormat, $responseSerializationFormat);
     }

Initialize Compression Serialization format Settings from Simple XML Reading from SDK.config
@Hao

Initialize Compression Serialization format Settings from Simple XML Reading from SDK . config


public static function intializaeServiceBaseURLAndLogger($xmlObj, $ippConfig)
     {
         // Initialize BaseUrl Configuration Object
        $ippConfig->BaseUrl = new BaseUrl();
         if (isset($xmlObj) &&
             isset($xmlObj->intuit->ipp->service->baseUrl)) {
             $responseAttr = $xmlObj->intuit->ipp->service->baseUrl->attributes();
             $ippConfig->BaseUrl->Qbo = (string)$responseAttr->qbo;
             $ippConfig->BaseUrl->Ipp = (string)$responseAttr->ipp;
         } else {
             throw new \Exception("Base Url is not available from Config file.");
         }

        // Initialize Logger
        if (isset($xmlObj) &&
                 isset($xmlObj->intuit->ipp->logger->requestLog)) {
            $requestLogAttr = $xmlObj->intuit->ipp->logger->requestLog->attributes();
            $ServiceRequestLoggingLocation = (string)$requestLogAttr->requestResponseLoggingDirectory;
            $EnableRequestResponseLogging = (string)$requestLogAttr->enableRequestResponseLogging;
            LocalConfigReader::setupLogger($ippConfig, $ServiceRequestLoggingLocation, $EnableRequestResponseLogging);
        } else {
            throw new \Exception("Log settings is not available from Config file.");
        }

     // A developer is forced to write in the same style.
     // This should be refactored
     if (isset($xmlObj) &&
              isset($xmlObj->intuit->ipp->contentWriter)) {
         $contentWriterAttr = $xmlObj->intuit->ipp->contentWriter->attributes();
         $strategy = ContentWriterSettings::checkStrategy((string)$contentWriterAttr->strategy);
         $prefix = (string)$contentWriterAttr->prefix;
         $exportDir = $contentWriterAttr->exportDirectory;
         $returnOject = $contentWriterAttr->returnObject;
         LocalConfigReader::setupContentWriter($ippConfig, $strategy, $prefix, $exportDir, $returnOject);
     } else {
         throw new \Exception("Content Writer Settings is not available from Config file.");
     }
     }

Initialize BaseURL and log Settings from Simple XML Reading from SDK.config
@Hao

Initialize BaseURL and log Settings from Simple XML Reading from SDK . config


public function getEntity($key)
    {
        foreach ($this->entities as $entityKey => $entityVal) {
            if ($entityKey==$key) {
                return $entityVal;
            }
        }
        return null;
    }

public function getEntity ( $ key ) { foreach ( $ this -> entities as $ entityKey => $ entityVal ) { if ( $ entityKey == $ key ) { return $ entityVal ; } } return null ; }

Gets the List of entity value with particular key
@var string key


public static function IsValidXml($inputString)
    {
        if (0!==strpos($inputString, '<')) {
            return false;
        }

        try {
            $doc = simplexml_load_string($inputString);
        } catch (\Exception $e) {
            return false;
        }

        return true;
    }

public static function IsValidXml ( $ inputString ) { if ( 0 !== strpos ( $ inputString , '<' ) ) { return false ; } try { $ doc = simplexml_load_string ( $ inputString ) ; } catch ( \ Exception $ e ) { return false ; } return true ; }

Validates the input string is a well formatted xml string
@param string inputString Input xml string
@return bool True if 'inputString' is a valid xml


public function verifyConfiguration()
    {
        if (($this->strategy === CoreConstants::EXPORT_STRATEGY) && !empty($this->strategy)) {
            if (is_null($this->exportDir)) {
                throw new SdkException("Invalid value for exportDirectory property. It can not be null with 'export' strategy. ");
            }
          //clear file cache
          clearstatcache();
            if (!file_exists($this->exportDir)) {
                throw new SdkException("Directory ({$this->exportDir}) doesn't exist.");
            }

            if (!is_dir($this->exportDir)) {
                throw new SdkException("Path ({$this->exportDir}) isn't a valid directory");
            }

            if (!is_writable($this->exportDir)) {
                throw new SdkException("Directory ({$this->exportDir}) isn't writable");
            }
        }
    }

Verifies current settigns
@throws SdkException


public static function loadWebServicesClassAndReturnNames($dir = null)
    {
        if ($dir == null) {
            $dir = dirname(__DIR__) . DIRECTORY_SEPARATOR . UtilityConstants::WEBHOOKSDIR;
        }

        $webhooksClassNames = array();

        foreach (glob("{$dir}/*.php") as $fileName) {
            require_once($fileName);
            //get class name
            $className = substr($fileName, strrpos($fileName, '/') + 1);
            //remove extension
            $classNameWithoutExtension = preg_replace('/\\.[^.\\s]{3,4}$/', '', $className);
            array_push($webhooksClassNames, $classNameWithoutExtension);
        }
        return $webhooksClassNames;
    }

public
static
function
loadWebServicesClassAndReturnNames
(
$
dir
=
)
{
if
(
$
dir
==
)
{
$
dir
=
dirname
(
__DIR__
)
.
DIRECTORY_SEPARATOR
.
UtilityConstants
::
WEBHOOKSDIR
;
}
$
webhooksClassNames
=
array
(
)
;
foreach
(
glob
(
"{$dir}/*.php"
)
as
$
fileName
)
{
require_once
(
$
fileName
)
;
//get class name
$
className
=
substr
(
$
fileName
,
strrpos
(
$
fileName
,
'/'
)
+
1
)
;
//remove extension
$
classNameWithoutExtension
=
preg_replace
(
'/\\.[^.\\s]{3,4}$/'
,
''
,
$
className
)
;
array_push
(
$
webhooksClassNames
,
$
classNameWithoutExtension
)
;
}
return
$
webhooksClassNames
;
}

Get all WebhooksService Class under WebhooksService directory

Pre-assumption: the WebhooksService dir is at the top layer of the SDK class.

@return array


public static function isValidWebhooksClass($className, $classCollection = null)
    {
        if (!isset($classCollection)) {
            $classCollection = ReflectionUtil::loadWebServicesClassAndReturnNames();
        }

        if (!isset($className) || trim($className) === '') {
            return null;
        }

        $singlerClassName = ClassNamingUtil::singularize($className);
        $capitalFirstSinglerClassName = ucfirst($singlerClassName);

        foreach ($classCollection as $k => $v) {
            if (strcmp($capitalFirstSinglerClassName, $v) == 0) {
                return $capitalFirstSinglerClassName;
            }
        }

        return null;
    }

public static function isValidWebhooksClass ( $ className , $ classCollection = null ) { if ( ! isset ( $ classCollection ) ) { $ classCollection = ReflectionUtil :: loadWebServicesClassAndReturnNames ( ) ; } if ( ! isset ( $ className ) || trim ( $ className ) === '' ) { return null ; } $ singlerClassName = ClassNamingUtil :: singularize ( $ className ) ; $ capitalFirstSinglerClassName = ucfirst ( $ singlerClassName ) ; foreach ( $ classCollection as $ k => $ v ) { if ( strcmp ( $ capitalFirstSinglerClassName , $ v ) == 0 ) { return $ capitalFirstSinglerClassName ; } } return null ; }

When given a WehbooksService name, check if the given class name is defined on the WehbooksService directory

@param $className
The object name that belongs to WebhooksService
@param null $classCollection
Default to be null. User can choose to pass their own collection
@return null|string
If the class name can be found in Webhooks Service, return the name; otherwise, return null.

When given a WehbooksService name check if the given class name is defined on the WehbooksService directory


public function getOptions()
    {
        $options = array();
        if (null !== $this->_actor) {
            $options['actor'] = $this->_actor;
        }

        if (null !== $this->_classmap) {
            $options['classmap'] = $this->_classmap;
        }

        if (null !== $this->_encoding) {
            $options['encoding'] = $this->_encoding;
        }

        if (null !== $this->_soapVersion) {
            $options['soap_version'] = $this->_soapVersion;
        }

        if (null !== $this->_uri) {
            $options['uri'] = $this->_uri;
        }

        if (null !== $this->_features) {
            $options['features'] = $this->_features;
        }

        if (null !== $this->_wsdlCache) {
            $options['cache_wsdl'] = $this->_wsdlCache;
        }

        return $options;
    }

public function getOptions ( ) { $ options = array ( ) ; if ( null !== $ this -> _actor ) { $ options [ 'actor' ] = $ this -> _actor ; } if ( null !== $ this -> _classmap ) { $ options [ 'classmap' ] = $ this -> _classmap ; } if ( null !== $ this -> _encoding ) { $ options [ 'encoding' ] = $ this -> _encoding ; } if ( null !== $ this -> _soapVersion ) { $ options [ 'soap_version' ] = $ this -> _soapVersion ; } if ( null !== $ this -> _uri ) { $ options [ 'uri' ] = $ this -> _uri ; } if ( null !== $ this -> _features ) { $ options [ 'features' ] = $ this -> _features ; } if ( null !== $ this -> _wsdlCache ) { $ options [ 'cache_wsdl' ] = $ this -> _wsdlCache ; } return $ options ; }

Return array of options suitable for using with SoapServer constructor

@return array


public function validateUrn($urn)
    {
        $scheme = parse_url($urn, PHP_URL_SCHEME);
        if ($scheme === false || $scheme === null) {
            require_once 'Zend/Soap/Server/Exception.php';
            throw new Zend_Soap_Server_Exception('Invalid URN');
        }

        return true;
    }

public
function
validateUrn
(
$
urn
)
{
$
scheme
=
parse_url
(
$
urn
,
PHP_URL_SCHEME
)
;
if
(
$
scheme
===
false
||
$
scheme
===
)
{
require_once
'Zend/Soap/Server/Exception.php'
;
throw
new
Zend_Soap_Server_Exception
(
'Invalid URN'
)
;
}
return
true
;
}

Check for valid URN

@param  string $urn
@return true
@throws Zend_Soap_Server_Exception on invalid URN


public function addFunction($function, $namespace = '')
    {
        // Bail early if set to SOAP_FUNCTIONS_ALL
        if ($this->_functions == SOAP_FUNCTIONS_ALL) {
            return $this;
        }

        if (is_array($function)) {
            foreach ($function as $func) {
                if (is_string($func) && function_exists($func)) {
                    $this->_functions[] = $func;
                } else {
                    require_once 'Zend/Soap/Server/Exception.php';
                    throw new Zend_Soap_Server_Exception('One or more invalid functions specified in array');
                }
            }
            $this->_functions = array_merge($this->_functions, $function);
        } elseif (is_string($function) && function_exists($function)) {
            $this->_functions[] = $function;
        } elseif ($function == SOAP_FUNCTIONS_ALL) {
            $this->_functions = SOAP_FUNCTIONS_ALL;
        } else {
            require_once 'Zend/Soap/Server/Exception.php';
            throw new Zend_Soap_Server_Exception('Invalid function specified');
        }

        if (is_array($this->_functions)) {
            $this->_functions = array_unique($this->_functions);
        }

        return $this;
    }

Attach a function as a server method

@param array|string $function Function name, array of function names to attach,
or SOAP_FUNCTIONS_ALL to attach all functions
@param  string $namespace Ignored
@return Zend_Soap_Server
@throws Zend_Soap_Server_Exception on invalid functions


public function setClass($class, $namespace = '', $argv = null)
    {
        if (isset($this->_class)) {
            require_once 'Zend/Soap/Server/Exception.php';
            throw new Zend_Soap_Server_Exception('A class has already been registered with this soap server instance');
        }

        if (!is_string($class)) {
            require_once 'Zend/Soap/Server/Exception.php';
            throw new Zend_Soap_Server_Exception('Invalid class argument (' . gettype($class) . ')');
        }

        if (!class_exists($class)) {
            require_once 'Zend/Soap/Server/Exception.php';
            throw new Zend_Soap_Server_Exception('Class "' . $class . '" does not exist');
        }

        $this->_class = $class;
        if (1 < func_num_args()) {
            $argv = func_get_args();
            array_shift($argv);
            $this->_classArgs = $argv;
        }

        return $this;
    }

Attach a class to a server

Accepts a class name to use when handling requests. Any additional
arguments will be passed to that class' constructor when instantiated.

See {@link setObject()} to set preconfigured object instances as request handlers.

@param string $class Class Name which executes SOAP Requests at endpoint.
@return Zend_Soap_Server
@throws Zend_Soap_Server_Exception if called more than once, or if class
does not exist


public function setObject($object)
    {
        if (!is_object($object)) {
            require_once 'Zend/Soap/Server/Exception.php';
            throw new Zend_Soap_Server_Exception('Invalid object argument ('.gettype($object).')');
        }

        if (isset($this->_object)) {
            require_once 'Zend/Soap/Server/Exception.php';
            throw new Zend_Soap_Server_Exception('An object has already been registered with this soap server instance');
        }

        $this->_object = $object;

        return $this;
    }

Attach an object to a server

Accepts an instanciated object to use when handling requests.

@param object $object
@return Zend_Soap_Server


public function getFunctions()
    {
        $functions = array();
        if (null !== $this->_class) {
            $functions = get_class_methods($this->_class);
        } elseif (null !== $this->_object) {
            $functions = get_class_methods($this->_object);
        }

        return array_merge((array) $this->_functions, $functions);
    }

public function getFunctions ( ) { $ functions = array ( ) ; if ( null !== $ this -> _class ) { $ functions = get_class_methods ( $ this -> _class ) ; } elseif ( null !== $ this -> _object ) { $ functions = get_class_methods ( $ this -> _object ) ; } return array_merge ( ( array ) $ this -> _functions , $ functions ) ; }

Return a server definition array

Returns a list of all functions registered with {@link addFunction()},
merged with all public methods of the class set with {@link setClass()}
(if any).

@access public
@return array


public function setPersistence($mode)
    {
        if (!in_array($mode, array(SOAP_PERSISTENCE_SESSION, SOAP_PERSISTENCE_REQUEST))) {
            require_once 'Zend/Soap/Server/Exception.php';
            throw new Zend_Soap_Server_Exception('Invalid persistence mode specified');
        }

        $this->_persistence = $mode;
        return $this;
    }

public
function
setPersistence
(
$
mode
)
{
if
(
!
in_array
(
$
mode
,
array
(
SOAP_PERSISTENCE_SESSION
,
SOAP_PERSISTENCE_REQUEST
)
)
)
{
require_once
'Zend/Soap/Server/Exception.php'
;
throw
new
Zend_Soap_Server_Exception
(
'Invalid persistence mode specified'
)
;
}
$
this
->
_persistence
=
$
mode
;
return
$
this
;
}

Set server persistence

@param int $mode
@return Zend_Soap_Server


protected function _getSoap()
    {
        $options = $this->getOptions();
        $server  = new SoapServer($this->_wsdl, $options);

        if (!empty($this->_functions)) {
            $server->addFunction($this->_functions);
        }

        if (!empty($this->_class)) {
            $args = $this->_classArgs;
            array_unshift($args, $this->_class);
            call_user_func_array(array($server, 'setClass'), $args);
        }

        if (!empty($this->_object)) {
            $server->setObject($this->_object);
        }

        if (null !== $this->_persistence) {
            $server->setPersistence($this->_persistence);
        }

        return $server;
    }

protected function _getSoap ( ) { $ options = $ this -> getOptions ( ) ; $ server = new SoapServer ( $ this -> _wsdl , $ options ) ; if ( ! empty ( $ this -> _functions ) ) { $ server -> addFunction ( $ this -> _functions ) ; } if ( ! empty ( $ this -> _class ) ) { $ args = $ this -> _classArgs ; array_unshift ( $ args , $ this -> _class ) ; call_user_func_array ( array ( $ server , 'setClass' ) , $ args ) ; } if ( ! empty ( $ this -> _object ) ) { $ server -> setObject ( $ this -> _object ) ; } if ( null !== $ this -> _persistence ) { $ server -> setPersistence ( $ this -> _persistence ) ; } return $ server ; }

Get SoapServer object

Uses {@link $_wsdl} and return value of {@link getOptions()} to instantiate
SoapServer object, and then registers any functions or class with it, as
well as peristence.

@return SoapServer


public function handle($request = null)
    {
        if (null === $request) {
            $request = file_get_contents('php://input');
        }

        // Set Zend_Soap_Server error handler
        $displayErrorsOriginalState = $this->_initializeSoapErrorContext();

        $setRequestException = null;
        /**
         * @see Zend_Soap_Server_Exception
         */
        require_once 'Zend/Soap/Server/Exception.php';
        try {
            $this->_setRequest($request);
        } catch (Zend_Soap_Server_Exception $e) {
            $setRequestException = $e;
        }

        $soap = $this->_getSoap();

        ob_start();
        if ($setRequestException instanceof Exception) {
            // Send SOAP fault message if we've catched exception
            $soap->fault("Sender", $setRequestException->getMessage());
        } else {
            try {
                $soap->handle($request);
            } catch (\Exception $e) {
                $fault = $this->fault($e);
                $soap->fault($fault->faultcode, $fault->faultstring);
            }
        }
        $this->_response = ob_get_clean();

        // Restore original error handler
        restore_error_handler();
        ini_set('display_errors', $displayErrorsOriginalState);

        if (!$this->_returnResponse) {
            echo $this->_response;
            return;
        }

        return $this->_response;
    }

Handle a request

Instantiates SoapServer object with options set in object, and
dispatches its handle() method.

$request may be any of:
- DOMDocument; if so, then cast to XML
- DOMNode; if so, then grab owner document and cast to XML
- SimpleXMLElement; if so, then cast to XML
- stdClass; if so, calls __toString() and verifies XML
- string; if so, verifies XML

If no request is passed, pulls request using php:://input (for
cross-platform compatability purposes).

@param DOMDocument|DOMNode|SimpleXMLElement|stdClass|string $request Optional request
@return void|string


public function deregisterFaultException($class)
    {
        if (in_array($class, $this->_faultExceptions, true)) {
            $index = array_search($class, $this->_faultExceptions);
            unset($this->_faultExceptions[$index]);
            return true;
        }

        return false;
    }

public function deregisterFaultException ( $ class ) { if ( in_array ( $ class , $ this -> _faultExceptions , true ) ) { $ index = array_search ( $ class , $ this -> _faultExceptions ) ; unset ( $ this -> _faultExceptions [ $ index ] ) ; return true ; } return false ; }

Deregister a fault exception from the fault exception stack

@param  string $class
@return boolean


public function fault($fault = null, $code = "Receiver")
    {
        if ($fault instanceof Exception) {
            $class = get_class($fault);
            if (in_array($class, $this->_faultExceptions)) {
                $message = $fault->getMessage();
                $eCode   = $fault->getCode();
                $code    = empty($eCode) ? $code : $eCode;
            } else {
                $message = 'Unknown error';
            }
        } elseif (is_string($fault)) {
            $message = $fault;
        } else {
            $message = 'Unknown error';
        }

        $allowedFaultModes = array(
            'VersionMismatch', 'MustUnderstand', 'DataEncodingUnknown',
            'Sender', 'Receiver', 'Server'
        );
        if (!in_array($code, $allowedFaultModes)) {
            $code = "Receiver";
        }

        return new SoapFault($code, $message);
    }

public
function
fault
(
$
fault
=
,
$
code
=
"Receiver"
)
{
if
(
$
fault
instanceof
Exception
)
{
$
class
=
get_class
(
$
fault
)
;
if
(
in_array
(
$
class
,
$
this
->
_faultExceptions
)
)
{
$
message
=
$
fault
->
getMessage
(
)
;
$
eCode
=
$
fault
->
getCode
(
)
;
$
code
=
empty
(
$
eCode
)
$
code
:
$
eCode
;
}
else
{
$
message
=
'Unknown error'
;
}
}
elseif
(
is_string
(
$
fault
)
)
{
$
message
=
$
fault
;
}
else
{
$
message
=
'Unknown error'
;
}
$
allowedFaultModes
=
array
(
'VersionMismatch'
,
'MustUnderstand'
,
'DataEncodingUnknown'
,
'Sender'
,
'Receiver'
,
'Server'
)
;
if
(
!
in_array
(
$
code
,
$
allowedFaultModes
)
)
{
$
code
=
"Receiver"
;
}
return
new
SoapFault
(
$
code
,
$
message
)
;
}

Generate a server fault

Note that the arguments are reverse to those of SoapFault.

If an exception is passed as the first argument, its message and code
will be used to create the fault object if it has been registered via
{@Link registerFaultException()}.

@link   http://www.w3.org/TR/soap12-part1/#faultcodes
@param  string|Exception $fault
@param  string $code SOAP Fault Codes
@return SoapFault


public function handlePhpErrors($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
    {
        throw $this->fault($errstr, "Receiver");
    }

public function handlePhpErrors ( $ errno , $ errstr , $ errfile = null , $ errline = null , array $ errcontext = null ) { throw $ this -> fault ( $ errstr , "Receiver" ) ; }

Throw PHP errors as SoapFaults

@param int $errno
@param string $errstr
@param string $errfile
@param int $errline
@param array $errcontext
@return void
@throws SoapFault


public function getAccessToken(){
       if(isset($this->oauth2AccessToken) && !empty($this->oauth2AccessToken)){
           return $this->oauth2AccessToken;
       }else{
           throw new SdkException("Can't get OAuth 2 Access Token Object. It is not set yet.");
       }
    }

Return the OAuth 2 Access Token Obj from the login helper.
@return OAuth2AccessToken   The OAuth 2 Access Token object

Return the OAuth 2 Access Token Obj from the login helper .


public function getAuthorizationCodeURL(){
        $parameters = array(
           'client_id' => $this->getClientID(),
           'scope' => $this->getScope(),
           'redirect_uri' => $this->getRedirectURL(),
           'response_type' => 'code',
           'state' => $this->getState()
       );
       $authorizationRequestUrl = CoreConstants::OAUTH2_AUTHORIZATION_REQUEST_URL;
       $authorizationRequestUrl .= '?' . http_build_query($parameters, null, '&', PHP_QUERY_RFC1738);
       return $authorizationRequestUrl;
    }

public function getAuthorizationCodeURL ( ) { $ parameters = array ( 'client_id' => $ this -> getClientID ( ) , 'scope' => $ this -> getScope ( ) , 'redirect_uri' => $ this -> getRedirectURL ( ) , 'response_type' => 'code' , 'state' => $ this -> getState ( ) ) ; $ authorizationRequestUrl = CoreConstants :: OAUTH2_AUTHORIZATION_REQUEST_URL ; $ authorizationRequestUrl .= '?' . http_build_query ( $ parameters , null , '&' , PHP_QUERY_RFC1738 ) ; return $ authorizationRequestUrl ; }

Step 1 of OAuth 2 protocol. Return the OAuth 2 Authorization URL.
@return String                THe Authorization URL

Step 1 of OAuth 2 protocol . Return the OAuth 2 Authorization URL .


public function refreshToken(){
       $refreshToken = $this->getAccessToken()->getRefreshToken();
       $http_header = $this->constructRefreshTokenHeader();
       $requestBody = $this->constructRefreshTokenBody($refreshToken);
       $intuitResponse = $this->curlHttpClient->makeAPICall(CoreConstants::OAUTH2_TOKEN_ENDPOINT_URL, CoreConstants::HTTP_POST, $http_header, $requestBody, null, true);
       $this->faultHandler = $intuitResponse->getFaultHandler();
       if($this->faultHandler) {
          throw new ServiceException("Refresh OAuth 2 Access token with Refresh Token failed. Body: [" . $this->faultHandler->getResponseBody() . "].", $this->faultHandler->getHttpStatusCode());
       }else{
          $this->faultHandler = false;
          $this->oauth2AccessToken = $this->parseNewAccessTokenFromResponse($intuitResponse->getBody());
          return $this->getAccessToken();
       }
    }

Get a new access token based on the refresh token
@return OAuth2AccessToken     A new OAuth2AccessToken that contains all the information(accessTokenkey, RefreshTokenKey, ClientID, and ClientSecret, Expiration Time, etc)


public function OAuth1ToOAuth2Migration($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret, $scope){
        $oauth1Encrypter = new OAuth1($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret);
        $parameters = array(
          'scope' => $scope,
          'redirect_uri' => "https://developer.intuit.com/v2/OAuth2Playground/RedirectUrl",
          'client_id' => $this->getClientID(),
          'client_secret' => $this->getClientSecret()
        );
        $baseURL = "https://developer.api.intuit.com/v2/oauth2/tokens/migrate";
        $authorizationHeaderInfo = $oauth1Encrypter->getOAuthHeader($baseURL, array(), "POST");
        $http_header = array(
          'Accept' => 'application/json',
          'Authorization' => $authorizationHeaderInfo,
          'Content-Type' => 'application/json'
        );
        $intuitResponse = $this->curlHttpClient->makeAPICall($baseURL, CoreConstants::HTTP_POST, $http_header, json_encode($parameters), null, false);
        $this->faultHandler = $intuitResponse->getFaultHandler();
        if($this->faultHandler) {
           throw new ServiceException("Migrate OAuth 1 token to OAuth 2 token failed. Body: [" . $this->faultHandler->getResponseBody() . "].", $this->faultHandler->getHttpStatusCode());
        }else{
           $this->faultHandler = false;
           $this->oauth2AccessToken = $this->parseNewAccessTokenFromResponse($intuitResponse->getBody());
           return $this->getAccessToken();
        }
    }

Provide OAuth 1 token generation for OAuth 2 token. This function currently is not available on QUickBooks Online yet.
@param String $consumerKey           The consumer key of OAuth 1
@param String $consumerSecre         The consumer Secre of OAuth 1
@param String $accessToken           The access token key of OAuth 1
@param String $accessTokenSecret     The access Token Secret key of OAuth 1
@param String $scope                 The scope of the key
@return OAuth2AccessToken

Provide OAuth 1 token generation for OAuth 2 token . This function currently is not available on QUickBooks Online yet .


private function parseNewAccessTokenFromResponse($body, $realmID = null){
        if(is_string($body)){
           $json_body = json_decode($body, true);
           if(json_last_error() === JSON_ERROR_NONE){
              $tokenExpiresTime = $json_body[CoreConstants::EXPIRES_IN];
              $refreshToken = $json_body[CoreConstants::OAUTH2_REFRESH_GRANTYPE];
              $refreshTokenExpiresTime = $json_body[CoreConstants::X_REFRESH_TOKEN_EXPIRES_IN];
              $accessToken = $json_body[CoreConstants::ACCESS_TOKEN];
              $this->checkIfEmptyValueReturned($tokenExpiresTime, $refreshToken, $refreshTokenExpiresTime, $accessToken);
              //If we have a response of OAuth 2 Access Token and the access token is not set, it must come from initial request. Create a dummy access token and update it.
              if(!isset($this->oauth2AccessToken)){
                  $this->oauth2AccessToken = new OAuth2AccessToken($this->getClientID(), $this->getClientSecret());
              }
              $this->oauth2AccessToken->updateAccessToken($tokenExpiresTime, $refreshToken, $refreshTokenExpiresTime, $accessToken);
              if(isset($realmID)){
                   $this->oauth2AccessToken->setRealmID($realmID);
              }
              return $this->oauth2AccessToken;
           }else{
              throw new SdkException("JSON DECODE encounters error:" . json_last_error());
           }
        }
    }

Parse the JSON Body to store the information to an OAuth 2 Access Token
@param String  $body       The JSON String contains all the OAuth 2 Access token information
@param String  $realmID    The realmID returned from authorization Code steps.It does not require for refresh token


private function checkIfEmptyValueReturned($tokenExpiresTime, $refreshToken, $refreshTokenExpiresTime, $accessToken){
      if(empty($tokenExpiresTime)){
        throw new SdkException("Error Retrieve RefreshToken from Response. Token Expires In Time is Empty.");
      }

      if(empty($refreshToken)){
        throw new SdkException("Error Retrieve RefreshToken from Response. Refresh Token is Empty.");
      }

      if(empty($refreshTokenExpiresTime)){
        throw new SdkException("Error Retrieve RefreshToken from Response. Refresh Token Expires Time is Empty.");
      }

      if(empty($accessToken)){
        throw new SdkException("Error Retrieve RefreshToken from Response. Access Token is Empty.");
      }
    }

A helper function to check Null value
@param String $tokenExpiresTime            access token expires time
@param String $refreshToken                Refreh Token
@param String $refreshTokenExpiresTime     refresh token expires time
@param String $accessToken                 accessToken


private function generateAuthorizationHeader(){
        $encodedClientIDClientSecrets = base64_encode($this->getClientID() . ':' . $this->getClientSecret());
        $authorizationheader = CoreConstants::OAUTH2_AUTHORIZATION_TYPE . $encodedClientIDClientSecrets;
        return $authorizationheader;
    }

private function generateAuthorizationHeader ( ) { $ encodedClientIDClientSecrets = base64_encode ( $ this -> getClientID ( ) . ':' . $ this -> getClientSecret ( ) ) ; $ authorizationheader = CoreConstants :: OAUTH2_AUTHORIZATION_TYPE . $ encodedClientIDClientSecrets ; return $ authorizationheader ; }

Generate Authorization Header based on Client ID and Client Serect
@return String   The authorization value


private function constructRefreshTokenHeader(){
        $authorizationHeaderInfo = $this->generateAuthorizationHeader();
        $http_header = array(
            'Accept' => CoreConstants::CONTENTTYPE_APPLICATIONJSON,
            'Authorization' => $authorizationHeaderInfo,
            'Content-Type' => CoreConstants::CONTENTTYPE_URLFORMENCODED,
            'connection'    => 'close'
        );
        return $http_header;
    }

private function constructRefreshTokenHeader ( ) { $ authorizationHeaderInfo = $ this -> generateAuthorizationHeader ( ) ; $ http_header = array ( 'Accept' => CoreConstants :: CONTENTTYPE_APPLICATIONJSON , 'Authorization' => $ authorizationHeaderInfo , 'Content-Type' => CoreConstants :: CONTENTTYPE_URLFORMENCODED , 'connection' => 'close' ) ; return $ http_header ; }

Generate header for refresh Token
@return Array Refresh Token header


private function checkResult($result)
  {
      $this->lastError = json_last_error();
      if (JSON_ERROR_NONE !== $this->lastError) {
          IdsExceptionManager::HandleException($this->getMessageFromErrorCode($this->lastError));
      }
            //TODO add logger here
        return $result;
  }

private
function
checkResult
(
$
result
)
{
$
this
->
lastError
=
json_last_error
(
)
;
if
(
JSON_ERROR_NONE
!==
$
this
->
lastError
)
{
IdsExceptionManager
::
HandleException
(
$
this
->
getMessageFromErrorCode
(
$
this
->
lastError
)
)
;
}
//TODO add logger here
return
$
result
;
}

Handle possible errors and react
@param mixed $result
@return mixed


private function getMessageFromErrorCode($error)
        {
            if (function_exists('json_last_error_msg')) {
                return json_last_error_msg();
            }
            $errors = array(
               JSON_ERROR_NONE             => null,
               JSON_ERROR_DEPTH            => 'Maximum stack depth exceeded',
               JSON_ERROR_STATE_MISMATCH   => 'Underflow or the modes mismatch',
               JSON_ERROR_CTRL_CHAR        => 'Unexpected control character found',
               JSON_ERROR_SYNTAX           => 'Syntax error, malformed JSON',
               JSON_ERROR_UTF8             => 'Malformed UTF-8 characters, possibly incorrectly encoded'
           );
            return array_key_exists($error, $errors) ? $errors[$error] : "Unknown error ({$error})";
        }

Support json_last_error_msg in PHP 5.2
@param string $error
@return string


private function convertObject($object, $limitToOne)
        {
            if ($object instanceof \stdClass) {
                $result = array();
                $vars = get_object_vars($object);
                if (empty($vars)) {
                    return null;
                }
                foreach ($vars as $key=>$value) {
                    $className = self::decorateIntuitEntityToPhpClassName($key);
                    if (!class_exists($className)) {
                        continue;
                    }
                    $entity = DomainEntityBuilder::create($className, $value);

                    if ($limitToOne) {
                        return $entity;
                    }
                    $result[] = $entity;
                }
                if (empty($result)) {
                    // Reutrn original parsed object and don't try to convert types
                    return $limitToOne ? $object : array($object);
                } else {
                    return $result;
                }
            }

            return $object;
        }

Converts stdClass objects into object with specified type
It tries to learn type from JSON responce

@param object $object
@param boolean $limitToOne
@return mixed (stdClass or domain model entity)


public function Serialize($entity)
    {
        $this->collectResourceURL($entity);
        $arrayObj = $this->customerConvertObjectToArray($entity);
        $array = $this->removeNullProperties($arrayObj);
        return $this->checkResult(json_encode($array, true));
    }

public function Serialize ( $ entity ) { $ this -> collectResourceURL ( $ entity ) ; $ arrayObj = $ this -> customerConvertObjectToArray ( $ entity ) ; $ array = $ this -> removeNullProperties ( $ arrayObj ) ; return $ this -> checkResult ( json_encode ( $ array , true ) ) ; }

Serializes the specified entity.
@param object entity The entity
@return string Returns the serialize entity in string format.


private function removeNullProperties($val){
        $filterArray = array_filter($val);
        $returned = array();
        foreach($filterArray as $k => $v){
          if(is_array($v)){
            if(FacadeHelper::isRecurrsiveArray($v)){
              $list = array();
              foreach($v as $kk => $vv){
                  $list[] = array_filter($vv);
              }
              $returned[$k] = $list;
            }
          }else{
            $returned[$k] = $v;
          }
        }
        return $returned;
    }

private function removeNullProperties ( $ val ) { $ filterArray = array_filter ( $ val ) ; $ returned = array ( ) ; foreach ( $ filterArray as $ k => $ v ) { if ( is_array ( $ v ) ) { if ( FacadeHelper :: isRecurrsiveArray ( $ v ) ) { $ list = array ( ) ; foreach ( $ v as $ kk => $ vv ) { $ list [ ] = array_filter ( $ vv ) ; } $ returned [ $ k ] = $ list ; } } else { $ returned [ $ k ] = $ v ; } } return $ returned ; }

The input will always be an asscoiate array
So we will judge based on this two situration


public function addComplexType($type)
    {
        if (!class_exists($type)) {
            require_once "Zend/Soap/Wsdl/Exception.php";
            throw new Zend_Soap_Wsdl_Exception(sprintf(
                "Cannot add a complex type %s that is not an object or where ".
                "class could not be found in 'DefaultComplexType' strategy.", $type
            ));
        }

        $dom = $this->getContext()->toDomDocument();
        $class = new ReflectionClass($type);

        $complexType = $dom->createElement('xsd:complexType');
        $complexType->setAttribute('name', $type);

        $all = $dom->createElement('xsd:all');

        foreach ($class->getProperties() as $property) {
            if ($property->isPublic() && preg_match_all('/@var\s+([^\s]+)/m', $property->getDocComment(), $matches)) {

                /**
                 * @todo check if 'xsd:element' must be used here (it may not be compatible with using 'complexType'
                 * node for describing other classes used as attribute types for current class
                 */
                $element = $dom->createElement('xsd:element');
                $element->setAttribute('name', $property->getName());
                $element->setAttribute('type', $this->getContext()->getType(trim($matches[1][0])));
                $all->appendChild($element);
            }
        }

        $complexType->appendChild($all);
        $this->getContext()->getSchema()->appendChild($complexType);
        $this->getContext()->addType($type);

        return "tns:$type";
    }

Add a complex type by recursivly using all the class properties fetched via Reflection.

@param  string $type Name of the class to be specified
@return string XSD Type for the given PHP type

Add a complex type by recursivly using all the class properties fetched via Reflection .


public function getWsdl($class = null)
    {
        /*
        if ($class != null) {
            $this->class = $class;
        } elseif ($this->class == null) {
            throw new \RuntimeException("No class defined");
        }

        if (!is_object($this->class) && !is_string($this->class)) {
            throw new \RuntimeException("Given class is neither class nor string");
        }

        if (is_string($this->class)) {
            if (!class_exists($this->class)) {
                throw new \RuntimeException("Class ".$class." is not found. Did you forget to include it?");
            }
            $this->class = new $this->class();
        }

        */

        //$this->refl = new \ReflectionClass($this->class);

        //$this->wsdl = new \Zend_Soap_Wsdl($this->refl->getShortName(),
        //                                 $this->namespaceToUrn($this->refl->getNamespaceName()));

        $factory = new wsdl\WsdlFactory($class, wsdl\WsdlFactory::WSDL_1_1);
        $this->wsdl = $factory->getImplementation();
        $this->wsdl->debug = true;
        /*
        $this->addTypes();
        $this->addMessages();
        $this->addPortType();
        $this->addBindings();

        $this->addServices();

        $dom = $this->wsdl->toDomDocument();
        if ($this->debug) {
            $dom->formatOutput = true;
        }*/

        return $this->wsdl->toXml();//$dom->saveXml();
    }

Ger WSDL file contents

@param string|object $class

@return string

@throws RuntimeException If class not defined
@throws RuntimeException If given class is neither class nor string
@throws RuntimeException If given class is not found, ie was not included before


private function addBindings()
    {
        $this->binding = $this->wsdl->addBinding($this->refl->getShortName().$this->bindingNameSuffix,
                                                 $this->targetNsPrefix.":".$this->getBindingTypeName());
        $this->wsdl->addSoapBinding($this->binding,
                                    $this->getSoapBindingStyle(),
                                    $this->getSoapBindingTransport());

        $this->addBindingOperations();
        return $this->binding;
    }

private function addBindings ( ) { $ this -> binding = $ this -> wsdl -> addBinding ( $ this -> refl -> getShortName ( ) . $ this -> bindingNameSuffix , $ this -> targetNsPrefix . ":" . $ this -> getBindingTypeName ( ) ) ; $ this -> wsdl -> addSoapBinding ( $ this -> binding , $ this -> getSoapBindingStyle ( ) , $ this -> getSoapBindingTransport ( ) ) ; $ this -> addBindingOperations ( ) ; return $ this -> binding ; }

Add bindings to WSDL

@return DomNode Binding node


private function addPortType()
    {
        $this->portType = $this->wsdl->addPortType($this->getPortName());
        $this->addPortOperations();

        return $this->portType;
    }

private function addPortType ( ) { $ this -> portType = $ this -> wsdl -> addPortType ( $ this -> getPortName ( ) ) ; $ this -> addPortOperations ( ) ; return $ this -> portType ; }

Add port type

@return DOMNode portType node


public function addTypes()
    {
        $methods = $this->getClassMethods();
        foreach ($methods as $method) {
            $data = $this->getMethodIO($method->name);
            $element = array('name' => $method->name,
                             'sequence' => array() );

            if (array_key_exists("params", $data)) {
                foreach ($data['params'] as $param) {
                    if ($this->isLocalType($this->getTypeName($param['type']))) {
                        array_push($element['sequence'], array('name' => $param['name'], 'type' => $this->getTypeName($param['type'])));
                    } else {
                        array_push($element['sequence'], array('ref' => $this->getTypeName($param['type'])));
                    }
                }
                $this->wsdl->addElement($element);
            }

            if (array_key_exists("return", $data)) {
                $return = "";
                if ($this->isLocalType($this->getTypeName($data['return']['type']))) {
                    $return = array('name' => $method->name.$this->responseSuffix,
                                 'sequence' => array(array('name' => 'Response', 'type' => $this->getTypeName($data['return']['type']))));
                } else {
                    $return = array('name' => $method->name.$this->responseSuffix,
                                 'sequence' => array(array('ref' => $this->getTypeName($data['return']['type']))));
                }

                $this->wsdl->addElement($return);
            }
        }
    }

public function addTypes ( ) { $ methods = $ this -> getClassMethods ( ) ; foreach ( $ methods as $ method ) { $ data = $ this -> getMethodIO ( $ method -> name ) ; $ element = array ( 'name' => $ method -> name , 'sequence' => array ( ) ) ; if ( array_key_exists ( "params" , $ data ) ) { foreach ( $ data [ 'params' ] as $ param ) { if ( $ this -> isLocalType ( $ this -> getTypeName ( $ param [ 'type' ] ) ) ) { array_push ( $ element [ 'sequence' ] , array ( 'name' => $ param [ 'name' ] , 'type' => $ this -> getTypeName ( $ param [ 'type' ] ) ) ) ; } else { array_push ( $ element [ 'sequence' ] , array ( 'ref' => $ this -> getTypeName ( $ param [ 'type' ] ) ) ) ; } } $ this -> wsdl -> addElement ( $ element ) ; } if ( array_key_exists ( "return" , $ data ) ) { $ return = "" ; if ( $ this -> isLocalType ( $ this -> getTypeName ( $ data [ 'return' ] [ 'type' ] ) ) ) { $ return = array ( 'name' => $ method -> name . $ this -> responseSuffix , 'sequence' => array ( array ( 'name' => 'Response' , 'type' => $ this -> getTypeName ( $ data [ 'return' ] [ 'type' ] ) ) ) ) ; } else { $ return = array ( 'name' => $ method -> name . $ this -> responseSuffix , 'sequence' => array ( array ( 'ref' => $ this -> getTypeName ( $ data [ 'return' ] [ 'type' ] ) ) ) ) ; } $ this -> wsdl -> addElement ( $ return ) ; } } }


public function addBindingOperations()
    {
        $methods = $this->getClassMethods();

        //@todo Check if binding is instantiated

        foreach ($methods as $method) {
            $data = $this->getMethodIO($method->name);
            $bindingInput = false;
            $bindingOutput = false;
            if (array_key_exists("params", $data)) {
                $bindingInput  = array('use' => 'literal');
            }

            if (array_key_exists("return", $data)) {
                $bindingOutput = array('use' => 'literal');
            }

            $operation     = $this->wsdl->addBindingOperation($this->binding, $method->name, $bindingInput, $bindingOutput);
            $soapOperation = $this->wsdl->addSoapOperation($operation, $this->namespaceToUrn($this->refl->getNamespaceName())."/".$method->name);
        }
    }


private function addPortOperations()
    {
        $methods = $this->getClassMethods();

        foreach ($methods as $method) {
            $data = $this->getMethodIO($method->name);

            $input         = false;
            $output        = false;
            $bindingInput  = false;
            $bindingOutput = false;

            if (array_key_exists("params", $data)) {
                $input = $this->targetNsPrefix.":".$method->name.$this->requestSuffix;
            }

            if (array_key_exists("return", $data)) {
                $output = $this->targetNsPrefix.":".$method->name.$this->responseSuffix;
            }

            $this->wsdl->addPortOperation($this->portType,
                                          $method->name,
                                          $input,
                                          $output);
        }
    }

private function addPortOperations ( ) { $ methods = $ this -> getClassMethods ( ) ; foreach ( $ methods as $ method ) { $ data = $ this -> getMethodIO ( $ method -> name ) ; $ input = false ; $ output = false ; $ bindingInput = false ; $ bindingOutput = false ; if ( array_key_exists ( "params" , $ data ) ) { $ input = $ this -> targetNsPrefix . ":" . $ method -> name . $ this -> requestSuffix ; } if ( array_key_exists ( "return" , $ data ) ) { $ output = $ this -> targetNsPrefix . ":" . $ method -> name . $ this -> responseSuffix ; } $ this -> wsdl -> addPortOperation ( $ this -> portType , $ method -> name , $ input , $ output ) ; } }


public function isLocalType($type)
    {
        if (preg_match('/:/', $type)) {
            list($ns, $typeName) = explode(":", $type);
            if ($ns == $this->targetNsPrefix || $ns == $this->xmlSchemaPreffix) {
                return true; // Local type
            } else {
                return false;
            }
        } else {
            // @todo - No namespace - local type
            return true;
        }
    }

public
function
isLocalType
(
$
type
)
{
if
(
preg_match
(
'/:/'
,
$
type
)
)
{
list
(
$
ns
,
$
typeName
)
=
explode
(
":"
,
$
type
)
;
if
(
$
ns
==
$
this
->
targetNsPrefix
||
$
ns
==
$
this
->
xmlSchemaPreffix
)
{
return
true
;
// Local type
}
else
{
return
false
;
}
}
else
{
// @todo - No namespace - local type
return
true
;
}
}

Return true if given type is local, false in case the type is not from xsd or tns namespaces

@param string $type QName type name

@return boolean

Return true if given type is local false in case the type is not from xsd or tns namespaces


private function addServices()
    {
        $this->wsdl->addService($this->getServiceName(), $this->getPortName(), $this->getBindingName(), $this->getLocation());
    }

private function addServices ( ) { $ this -> wsdl -> addService ( $ this -> getServiceName ( ) , $ this -> getPortName ( ) , $ this -> getBindingName ( ) , $ this -> getLocation ( ) ) ; }


private function getTargetNS($xpath)
    {
        $query   = "//*[local-name()='schema' and namespace-uri()='http://www.w3.org/2001/XMLSchema']/@targetNamespace";
        $targetNs =  $xpath->query($query);

        if ($targetNs) {
            foreach ($targetNs as $entry) {
                return $entry->nodeValue;
            }
        }
    }

Return target namespace for given DOMXPath object

@param DOMXPath $xpath DOMXPath Object

@return string


public function getNamespaces($xpath)
    {
        $query   = "//namespace::*";
        $entries =  $xpath->query($query);
        $nspaces = array();

        foreach ($entries as $entry) {
            if ($entry->nodeValue == "http://www.w3.org/2001/XMLSchema") {
                $this->xsdNs = preg_replace('/xmlns:(.*)/', "$1", $entry->nodeName);
            }
            if (//$entry->nodeName != $this->xsdNs
            //&&
            $entry->nodeName != 'xmlns:xml') {
                if (preg_match('/:/', $entry->nodeName)) {
                    $nodeName = explode(':', $entry->nodeName);
                    $nspaces[$nodeName[1]] = $entry->nodeValue;
                } else {
                    $nspaces[$entry->nodeName] = $entry->nodeValue;
                }
            }
        }
        return $nspaces;
    }

public
function
getNamespaces
(
$
xpath
)
{
$
query
=
"//namespace::*"
;
$
entries
=
$
xpath
->
query
(
$
query
)
;
$
nspaces
=
array
(
)
;
foreach
(
$
entries
as
$
entry
)
{
if
(
$
entry
->
nodeValue
==
"http://www.w3.org/2001/XMLSchema"
)
{
$
this
->
xsdNs
=
preg_replace
(
'/xmlns:(.*)/'
,
"$1"
,
$
entry
->
nodeName
)
;
}
if
(
//$entry->nodeName != $this->xsdNs
//&&
$
entry
->
nodeName
!=
'xmlns:xml'
)
{
if
(
preg_match
(
'/:/'
,
$
entry
->
nodeName
)
)
{
$
nodeName
=
explode
(
':'
,
$
entry
->
nodeName
)
;
$
nspaces
[
$
nodeName
[
1
]
]
=
$
entry
->
nodeValue
;
}
else
{
$
nspaces
[
$
entry
->
nodeName
]
=
$
entry
->
nodeValue
;
}
}
}
return
$
nspaces
;
}

Return array of namespaces of the document

@param DOMXPath $xpath

@return array


public function saveClasses($dir, $createDirectory = false)
    {
        $this->setXmlSource($this->getXML()->saveXML());
        $this->savePhpFiles($dir, $createDirectory);
    }

public function saveClasses ( $ dir , $ createDirectory = false ) { $ this -> setXmlSource ( $ this -> getXML ( ) -> saveXML ( ) ) ; $ this -> savePhpFiles ( $ dir , $ createDirectory ) ; }

Save generated classes to directory

@param string  $dir             Directory to save classes to
@param boolean $createDirectory [optional] Create directory, false by default

@return void


public function loadIncludes($dom, $filepath = '', $namespace = '')
    {
        $xpath = new \DOMXPath($dom);
        $query = "//*[local-name()='include' and namespace-uri()='http://www.w3.org/2001/XMLSchema']";
        $includes = $xpath->query($query);

        foreach ($includes as $entry) {
            $parent = $entry->parentNode;
            $xsd = new \DOMDocument();
            $xsdFileName = realpath($filepath.DIRECTORY_SEPARATOR.$entry->getAttribute("schemaLocation"));
            if ($this->debug) {
                print('Including '.$xsdFileName."\n");
            }

            if (!file_exists($xsdFileName)) {
                if ($this->debug) {
                    print $xsdFileName. " is not found \n";
                }
                continue;
            }

            $result = $xsd->load($xsdFileName,
            LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NOENT|LIBXML_XINCLUDE);
            if ($result) {
                $mxpath = new \DOMXPath($xsd);
                $this->shortNamespaces = array_merge($this->shortNamespaces, $this->getNamespaces($mxpath));
            }
            foreach ($xsd->documentElement->childNodes as $node) {
                if ($node->nodeName == $this->xsdNs.":include") {
                    $loc = realpath($filepath.DIRECTORY_SEPARATOR.$node->getAttribute('schemaLocation'));
                    $node->setAttribute('schemaLocation', $loc);
                    if ($this->debug) {
                        print('Change included schema location to '.$loc." \n");
                    }
                    $newNode = $dom->importNode($node, true);
                    $parent->insertBefore($newNode, $entry);
                } else {
                    if ($namespace != '') {
                        $newNodeNs = $xsd->createAttribute("namespace");
                        $textEl = $xsd->createTextNode($namespace);
                        $newNodeNs->appendChild($textEl);
                        $node->appendChild($newNodeNs);
                    }

                    $newNode = $dom->importNode($node, true);
                    $parent->insertBefore($newNode, $entry);
                }
            }
            $parent->removeChild($entry);
        }

/*         $xpath = new \DOMXPath($dom);
        $query = "//*[local-name()='include' and namespace-uri()='http://www.w3.org/2001/XMLSchema']";
        $includes = $xpath->query($query);
        if ($includes->length != 0) {
            $dom = $this->loadIncludes($dom);
        } */

        if ($this->debug) {
            print_r("\n------------------------------------\n");
        }

        return $dom;
    }

Load includes in XML Schema

@param DOMDocument $dom       Instance of DOMDocument
@param string      $filepath
@param string	  $namespace

@return void


public function getXML()
    {
        try {
            $xsl    = new \XSLTProcessor();
            $xslDom = new \DOMDocument();
            $xslDom->load(dirname(__FILE__) . "/xsd2php2.xsl");
            $xsl->registerPHPFunctions();
            $xsl->importStyleSheet($xslDom);
            $dom = $xsl->transformToDoc($this->dom);
            $dom->formatOutput = true;

            return $dom;
        } catch (\Exception $e) {
            throw new \Exception(
                    "Error interpreting XSD document (".$e->getMessage().")");
        }
    }

public
function
getXML
(
)
{
try
{
$
xsl
=
new
\
XSLTProcessor
(
)
;
$
xslDom
=
new
\
DOMDocument
(
)
;
$
xslDom
->
load
(
dirname
(
__FILE__
)
.
"/xsd2php2.xsl"
)
;
$
xsl
->
registerPHPFunctions
(
)
;
$
xsl
->
importStyleSheet
(
$
xslDom
)
;
$
dom
=
$
xsl
->
transformToDoc
(
$
this
->
dom
)
;
$
dom
->
formatOutput
=
true
;
return
$
dom
;
}
catch
(
\
Exception
$
e
)
{
throw
new
\
Exception
(
"Error interpreting XSD document ("
.
$
e
->
getMessage
(
)
.
")"
)
;
}
}

Convert XSD to XML suitable for further processing

@return string XML string

@return DOMDocument


private function savePhpFiles($dir, $createDirectory = false)
    {
        if (!file_exists($dir) && $createDirectory === false) {
            throw new \RuntimeException($dir." does not exist");
        }

        if (!file_exists($dir) && $createDirectory === true) {
            //@todo Implement Recursive mkdir
            mkdir($dir, 0777, true);
        }

        $classes = $this->getPHP();

        foreach ($classes as $fullkey => $value) {
            $keys = explode("|", $fullkey);
            $key = $keys[0];
            $namespace = $this->namespaceToPath($keys[1]);
            if ($this->overrideAsSingleNamespace) {
                $targetDir = $dir;
            } else {
                $targetDir = $dir.DIRECTORY_SEPARATOR.$namespace;
            }
            if (!file_exists($targetDir)) {
                mkdir($targetDir, 0777, true);
            }
            file_put_contents($targetDir.DIRECTORY_SEPARATOR.$key.'.php', $value);
        }
        if ($this->debug) {
            echo "Generated classes saved to ".$dir;
        }
    }

private
function
savePhpFiles
(
$
dir
,
$
createDirectory
=
false
)
{
if
(
!
file_exists
(
$
dir
)
&&
$
createDirectory
===
false
)
{
throw
new
\
RuntimeException
(
$
dir
.
" does not exist"
)
;
}
if
(
!
file_exists
(
$
dir
)
&&
$
createDirectory
===
true
)
{
//@todo Implement Recursive mkdir
mkdir
(
$
dir
,
0777
,
true
)
;
}
$
classes
=
$
this
->
getPHP
(
)
;
foreach
(
$
classes
as
$
fullkey
=>
$
value
)
{
$
keys
=
explode
(
"|"
,
$
fullkey
)
;
$
key
=
$
keys
[
0
]
;
$
namespace
=
$
this
->
namespaceToPath
(
$
keys
[
1
]
)
;
if
(
$
this
->
overrideAsSingleNamespace
)
{
$
targetDir
=
$
dir
;
}
else
{
$
targetDir
=
$
dir
.
DIRECTORY_SEPARATOR
.
$
namespace
;
}
if
(
!
file_exists
(
$
targetDir
)
)
{
mkdir
(
$
targetDir
,
0777
,
true
)
;
}
file_put_contents
(
$
targetDir
.
DIRECTORY_SEPARATOR
.
$
key
.
'.php'
,
$
value
)
;
}
if
(
$
this
->
debug
)
{
echo
"Generated classes saved to "
.
$
dir
;
}
}

Save PHP files to directory structure

@param string  $dir             Directory to save files to
@param boolean $createDirectory Create $dir directory if it doesn't exist

@throws RuntimeException if given directory does not exist

@return void


public function namespaceToPhp($xmlNS)
    {
        $ns = $xmlNS;
        $ns = $this->expandNS($ns);
        if (preg_match('/urn:/', $ns)) {
            //@todo check if there are any components of namespace which are
            $ns = preg_replace('/-/', '_', $ns);
            $ns = preg_replace('/urn:/', '', $ns);
            $ns = preg_replace('/:/', '\\', $ns);
        }

        /**
         if (preg_match('/http:\/\//', $ns)) {
         $ns = preg_replace('/http:\/\//', '', $ns);
         $ns = preg_replace('/\//','\\', $ns);
         $ns = preg_replace('/\./', '\\',$ns);
         }*/

        $matches = array();
        if (preg_match("#((http|https|ftp)://(\S*?\.\S*?))(\s|\;|\)|\]|\[|\{|\}|,|\"|'|:|\<|$|\.\s)#", $ns, $matches)) {
            $elements = explode("/", $matches[3]);
            $domain = $elements[0];
            array_shift($elements);
            //print_r($domain."\n");
            $ns = implode("\\", array_reverse(explode(".", $domain)));
            //$ns = preg_replace('/\./', '\\', );
            //print $ns."\n";
            foreach ($elements as $key => $value) {
                if ($value != '') {
                    $value = preg_replace('/\./', '_', $value);
                    $ns .= "\\" . $value;
                }
            }
        }

        $ns = explode('\\', $ns);
        $i = 0;
        foreach ($ns as $elem) {
            if (preg_match('/^([0-9]+)(.*)$/', $elem)) {
                $ns[$i] = "_".$elem;
            }

            if (in_array($elem, $this->reservedWords)) {
                $ns[$i] = "_".$elem;
            }
            $i++;
        }

        $ns = implode('\\', $ns);

        return $ns;
    }

Convert XML URI to PHP complient namespace

@param string $xmlNS XML URI

@return string


public function setBaseURL($baseURL){
      if(strcasecmp($baseURL, CoreConstants::DEVELOPMENT_SANDBOX) == 0){
         $this->baseURL = CoreConstants::SANDBOX_DEVELOPMENT;
      }else if(strcasecmp($baseURL, CoreConstants::PRODUCTION_QBO) == 0){
         $this->baseURL = CoreConstants::QBO_BASEURL;
      }else{
         $this->baseURL = $baseURL;
      }

    }

public function setBaseURL ( $ baseURL ) { if ( strcasecmp ( $ baseURL , CoreConstants :: DEVELOPMENT_SANDBOX ) == 0 ) { $ this -> baseURL = CoreConstants :: SANDBOX_DEVELOPMENT ; } else if ( strcasecmp ( $ baseURL , CoreConstants :: PRODUCTION_QBO ) == 0 ) { $ this -> baseURL = CoreConstants :: QBO_BASEURL ; } else { $ this -> baseURL = $ baseURL ; } }

Set the baseURL associated with this Acess Token
@param string $baseUrl            The base URL


public function getRefreshTokenValidationPeriodInSeconds(){
      if(isset($this->refreshTokenValidationPeriod) && !empty($this->refreshTokenValidationPeriod))
      {
          return $this->refreshTokenValidationPeriod;
      }else{
        throw new SdkException("The validation period for OAuth 2 refresh Token is not set.");
      }
    }

Return the number of seconds for refresh token
The implementation of Quickbooks Online OAuth 2 always return an 8726400 seconds refresh token. This method is not useful now
@return int

Return the number of seconds for refresh token The implementation of Quickbooks Online OAuth 2 always return an 8726400 seconds refresh token . This method is not useful now


public function getAccessTokenValidationPeriodInSeconds(){
      if(isset($this->accessTokenValidationPeriod) && !empty($this->accessTokenValidationPeriod))
      {
          return $this->accessTokenValidationPeriod;
      }else{
        throw new SdkException("The validation period for OAuth 2 access Token is not set.");
      }
    }

Return the number of seconds for access token
The implementation of Quickbooks Online OAuth 2 always return an one hour access token. This method is not useful
@return int

Return the number of seconds for access token The implementation of Quickbooks Online OAuth 2 always return an one hour access token . This method is not useful


public function getRefreshToken(){
        if(isset($this->refresh_token) && !empty($this->refresh_token))  return $this->refresh_token;
        else throw new SdkException("The OAuth 2 Refresh Token is not set in the Access Token Object.");
    }


public function getAccessToken(){
      if(isset($this->accessTokenKey) && !empty($this->accessTokenKey))  return $this->accessTokenKey;
      else throw new SdkException("The OAuth 2 Access Token is not set in the Access Token Object.");
    }


public function updateAccessToken($tokenExpiresTime, $refreshToken, $refreshTokenExpiresTime, $accessToken){
       $this->setAccessToken($accessToken);
       $this->setRefreshToken($refreshToken);
       $this->setAccessTokenValidationPeriodInSeconds($tokenExpiresTime);
       $this->setRefreshTokenValidationPeriodInSeconds($refreshTokenExpiresTime);
       $this->setAccessTokenExpiresAt(time() + $tokenExpiresTime);
       $this->setRefreshTokenExpiresAt(time() + $refreshTokenExpiresTime);
    }

Update an access token after creating a new access token or making a refresh tokan API call
@param int      $tokenExpiresTime          The number of seconds that access token expired. Always 3600 seconds.
@param String   $refreshToken              The OAuth 2 Refresh Token returned from refresh token API call or generated from a new request.
@param int      $refreshTokenExpiresTime   The number of seconds that refresh token expired. Always 8726400 seconds.
@param String   $accessToken               The OAuth 2 Access Token returned from refresh token API call or generated from a new request.


public static function getPostXmlFromArbitraryEntity($entity, &$urlResource)
    {
        if (null==$entity) {
            return false;
        }

        $xmlElementName = XmlObjectSerializer::cleanPhpClassNameToIntuitEntityName(get_class($entity));
        $xmlElementName = trim($xmlElementName);
        $urlResource = strtolower($xmlElementName);
        $httpsPostBody = XmlObjectSerializer::getXmlFromObj($entity);
        return $httpsPostBody;
    }

public static function getPostXmlFromArbitraryEntity ( $ entity , & $ urlResource ) { if ( null == $ entity ) { return false ; } $ xmlElementName = XmlObjectSerializer :: cleanPhpClassNameToIntuitEntityName ( get_class ( $ entity ) ) ; $ xmlElementName = trim ( $ xmlElementName ) ; $ urlResource = strtolower ( $ xmlElementName ) ; $ httpsPostBody = XmlObjectSerializer :: getXmlFromObj ( $ entity ) ; return $ httpsPostBody ; }

Marshall a POPO object to be XML

@param IPPIntuitEntity $entity The POPO object
@param string $urlResource the type of the POPO object
@return string the XML of the POPO object


private static function PhpObjFromXml($className, $xmlStr)
    {
        $className = trim($className);
        if (class_exists($className, CoreConstants::USE_AUTOLOADER)) {
            $phpObj = new $className;
        } elseif (class_exists(CoreConstants::NAMEPSACE_DATA_PREFIX . $className, CoreConstants::USE_AUTOLOADER)) {
            $className = CoreConstants::NAMEPSACE_DATA_PREFIX . $className;
            $phpObj = new $className;
        } else {
            throw new \Exception("Can't find corresponding CLASS for className" . $className . "during unmarshall XML into POPO Object");
        }
        $bind = new Bind(CoreConstants::PHP_CLASS_PREFIX);
        $bind->overrideAsSingleNamespace='http://schema.intuit.com/finance/v3';
        $bind->bindXml($xmlStr, $phpObj);
        return $phpObj;
    }

Unmarshall XML into a POPO object, presumably the XML came from an IPP v3 API call

@param string XML that conforms to IPP v3 XSDs
@return object POPOObject $phpObj resulting POPO object

Unmarshall XML into a POPO object presumably the XML came from an IPP v3 API call


private static function ParseArbitraryResultObjects($responseXml, $bLimitToOne)
    {
        if (!$responseXml) {
            return null;
        }

        $resultObject = null;
        $resultObjects = null;

        $responseXmlObj = simplexml_load_string($responseXml);
        foreach ($responseXmlObj as $oneXmlObj) {
            $oneXmlElementName = (string)$oneXmlObj->getName();

            //The handling falut here is a little too simple. add more support for future
            //@hao
            if ('Fault'==$oneXmlElementName) {
                return null;
            }
            $phpClassName = XmlObjectSerializer::decorateIntuitEntityToPhpClassName($oneXmlElementName);
            $onePhpObj = XmlObjectSerializer::PhpObjFromXml($phpClassName, $oneXmlObj->asXML());
            $resultObject = $onePhpObj;
            $resultObjects[] = $onePhpObj;

            // Caller may be anticipating ONLY one object in result
            if ($bLimitToOne) {
                break;
            }
        }

        if ($bLimitToOne) {
            return $resultObject;
        } else {
            return $resultObjects;
        }
    }

Parse an XML string into an array of IPPIntuitEntity objects

@param string $responseXml XML string to parse
@param bool $bLimitToOne Signals to only parse the first element
@return array of IPPIntuitEntity objects


public function setupOption($k, $v){
      if($this->isCurlSet()){
        curl_setopt($this->curl, $k, $v);
      } else {
        throw new SdkException("cURL instance is not set when calling setup Option.");
      }
  }

set options for curl
@param String $k The key
@param String $v The value


public function versionOfTLS(){
      $tlsVersion = "";
      $curl = curl_init();
      curl_setopt($curl, CURLOPT_URL, "https://www.howsmyssl.com/a/check");
      curl_setopt($curl, CURLOPT_SSLVERSION, 6);
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
      $curlVersionResponse = curl_exec($curl);
      if($curlVersionResponse === false){
         throw new SdkException("Error in checking cURL version for TLS 1.2. Error Num:[" . curl_errno($curl) . "] Error message:[" . curl_error($curl) . "]");
      }else{
         $tlsVersion = json_decode($curlVersionResponse)->tls_version;
      }
      curl_close($curl);
      return $tlsVersion;
  }

Set the curl TLS Version and check if TLS 1.2 is supported
@return int TLSversion

Set the curl TLS Version and check if TLS 1 . 2 is supported


public static function HandleException($errorMessage=null, $errorCode=null, $source=null, $innerException=null)
    {
        $message = implode(", ", array($errorMessage, $errorCode, $source));
        throw new IdsException($message);
    }

public
static
function
HandleException
(
$
errorMessage
=
,
$
errorCode
=
,
$
source
=
,
$
innerException
=
)
{
$
message
=
implode
(
", "
,
array
(
$
errorMessage
,
$
errorCode
,
$
source
)
)
;
throw
new
IdsException
(
$
message
)
;
}

Handles Exception thrown to the user.
@param string errorMessage Error Message
@param string errorCode Error Code.
@param string source Source of the exception.
@param IdsException innerException Ids Exception


private function verifyVariableType($value)
    {
        // if value can be mapped to simple type
       if (in_array(strtolower($value), array("string","float","double","boolean", "integer"))) {
           return new SimpleEntity(strtolower($value));
       }

       // generate names
       // try it
       foreach ($this->generateObjectNames($value) as $name) {
           $name = $this->addNameSpaceToPotentialClassName($name);
           if (class_exists($name)) {
               return new ObjectEntity($name);
           }
       }

        return new UnknownEntity($value);
    }

Verifies type and creates entity object
@param string $value
@return AbstractEntity


private function generateObjectNames($value)
    {
        $reversiveStack = array();
        $reversiveStack[] = $value; // add original value. It will be called last
        $reversiveStack[] = $this->removeArrayBrackets($value); //
        $reversiveStack[] = $this->getIntuitName($this->removeArrayBrackets($value));
        $reversiveStack[] = $this->getIntuitName($this->removeArrayBrackets($this->getClassNameFromPackagePath($value)));
        $reversiveStack[] = $this->removeArrayBrackets($this->getClassNameFromPackagePath($value));
        $reversiveStack[] = $this->getClassNameFromPackagePath($value);
        return array_reverse($reversiveStack);
    }

Returns order list of possible valid names of object type
@param string $value
@return array


private function completeProperty($a, ReflectionProperty $p)
    {
        if (!$a instanceof AbstractEntity) {
            throw new InvalidArgumentException("Expected instance of AbstractEntity here");
        }
        $a->setName($p->getName());
        $a->setClass($p->getDeclaringClass());
    }

Finilizes created metadata description with few more info
@param AbstractEntity $a
@param ReflectionProperty $p
@throws InvalidArgumentException


public function unmarshal($xml)
    {
        // Get all namespaces
        $this->dom = new \DOMDocument();
        if ($this->debug) {
            $this->dom->formatOutput = true;
        }
        $this->dom->loadXML($xml);

        $this->namespaces =  $this->getDocNamespaces($this->dom);

        // Find targetNamespace

        $xpath = new \DOMXPath($this->dom);
        $query = ".";
        $root = $xpath->query($query);
        $ns = $code = "";
        foreach ($root as $rt) {
            list($ns, $name) = $this->parseQName($rt->nodeName, true);
        }

        $className = $this->urnToPhpName($ns)."\\".$this->classPrefix.$name;

        if (!class_exists($className, CoreConstants::USE_AUTOLOADER)) {
            throw new \RuntimeException('Class '.$className. ' is not found. Make sure it was included');
        }

        $binding = new $className();

        return $this->bindXml($xml, $binding);

        // Instantiate class
        // Assign corresponding nodes to properties/classes
        // return PHP binding
    }

Unmarshal XML string to corresponding PHP binding

@param string $xml XML string to unmarshal

@return object PHP binding object


public static function GetSerializer($serviceContext, $isRequest)
    {
        $serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "GetSerializer");

        $serializer = null;
        if ($isRequest) {
            switch ($serviceContext->IppConfiguration->Message->Request->SerializationFormat) {
                case SerializationFormat::Xml:
                              $serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "GetSerializer(Request): Xml");
                    $serializer = new XmlObjectSerializer();
                    break;
                case SerializationFormat::Json:
                              $serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "GetSerializer(Request): JSON");
                    $serializer = new JsonObjectSerializer();
                    break;
                case SerializationFormat::Custom:
                    // TODO: check whtether this is possible
                    // $this->serializer = $serviceContext->IppConfiguration->Message->Request->CustomSerializer;
                              $serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "GetSerializer(Request): Custom");
                    break;
            }
        } else {
            switch ($serviceContext->IppConfiguration->Message->Response->SerializationFormat) {
                case SerializationFormat::Xml:
                              $serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "GetSerializer(Response): XML");
                    $serializer = new XmlObjectSerializer();
                    break;
                case SerializationFormat::Json:
                              $serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "GetSerializer(Response): JSON");
                    $serializer = new JsonObjectSerializer();
                    break;
                case SerializationFormat::Custom:
                    // TODO: check whtether this is possible
                    // $this->serializer = $serviceContext->IppConfiguration->Message->Response->CustomSerializer;
                              $serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "GetSerializer(Response): Custom");
                    break;
            }
        }

        return $serializer;
    }

Gets the serializer mechanism using the service context and the depending on the request and response.
@param ServiceContext serviceContext The service context object.
@param bool isRequest Specifies whether to return serializer mechanism for request or response.
@return IEntitySerializer The Serializer mechanism.

Gets the serializer mechanism using the service context and the depending on the request and response .


public static function GetCompressor($serviceContext, $isRequest)
    {
        $compressor = null;
        if ($isRequest) {
            switch ($serviceContext->IppConfiguration->Message->Request->CompressionFormat) {
                case CompressionFormat::GZip:
                    $compressor = new GZipCompressor();
                    break;
                case CompressionFormat::Deflate:
                    $compressor = new DeflateCompressor();
                    break;
            }
        } else {
            switch ($serviceContext->IppConfiguration->Message->Response->CompressionFormat) {
                case CompressionFormat::GZip:
                    $compressor = new GZipCompressor();
                    break;
                case CompressionFormat::Deflate:
                    $compressor = new DeflateCompressor();
                    break;
            }
        }

        return $compressor;
    }

public static function GetCompressor ( $ serviceContext , $ isRequest ) { $ compressor = null ; if ( $ isRequest ) { switch ( $ serviceContext -> IppConfiguration -> Message -> Request -> CompressionFormat ) { case CompressionFormat :: GZip : $ compressor = new GZipCompressor ( ) ; break ; case CompressionFormat :: Deflate : $ compressor = new DeflateCompressor ( ) ; break ; } } else { switch ( $ serviceContext -> IppConfiguration -> Message -> Response -> CompressionFormat ) { case CompressionFormat :: GZip : $ compressor = new GZipCompressor ( ) ; break ; case CompressionFormat :: Deflate : $ compressor = new DeflateCompressor ( ) ; break ; } } return $ compressor ; }

Gets the compression mechanism using the service context and the depending on the request and response.
@param ServiceContext serviceContext The service context object.
@param bool isRequest Specifies whether to return compression mechanism for reqeust or response.
@return CompressorBase The Compression mechanism.

Gets the compression mechanism using the service context and the depending on the request and response .


public static function GetRequestLogging($serviceContext)
    {
        $requestLogger = null;
        try {
            if (isset($serviceContext->IppConfiguration) &&
                isset($serviceContext->IppConfiguration->Logger) &&
                isset($serviceContext->IppConfiguration->Logger->RequestLog) &&
                isset($serviceContext->IppConfiguration->Logger->RequestLog->EnableRequestResponseLogging) &&
                isset($serviceContext->IppConfiguration->Logger->RequestLog->ServiceRequestLoggingLocation)) {
                $requestLogger = new LogRequestsToDisk(
                    $serviceContext->IppConfiguration->Logger->RequestLog->EnableRequestResponseLogging,
                    $serviceContext->IppConfiguration->Logger->RequestLog->ServiceRequestLoggingLocation);
            } else {
                $requestLogger = new LogRequestsToDisk(false, null);
            }
        } catch (\Exception $e) {
            $requestLogger = new LogRequestsToDisk(false, null);
        }

        return $requestLogger;
    }

public static function GetRequestLogging ( $ serviceContext ) { $ requestLogger = null ; try { if ( isset ( $ serviceContext -> IppConfiguration ) && isset ( $ serviceContext -> IppConfiguration -> Logger ) && isset ( $ serviceContext -> IppConfiguration -> Logger -> RequestLog ) && isset ( $ serviceContext -> IppConfiguration -> Logger -> RequestLog -> EnableRequestResponseLogging ) && isset ( $ serviceContext -> IppConfiguration -> Logger -> RequestLog -> ServiceRequestLoggingLocation ) ) { $ requestLogger = new LogRequestsToDisk ( $ serviceContext -> IppConfiguration -> Logger -> RequestLog -> EnableRequestResponseLogging , $ serviceContext -> IppConfiguration -> Logger -> RequestLog -> ServiceRequestLoggingLocation ) ; } else { $ requestLogger = new LogRequestsToDisk ( false , null ) ; } } catch ( \ Exception $ e ) { $ requestLogger = new LogRequestsToDisk ( false , null ) ; } return $ requestLogger ; }

Gets the Request Response Logging mechanism.
@param ServiceContext serviceContext The serivce context object.
@return LogRequestsToDisk Returns value which specifies the request response logging mechanism.

Gets the Request Response Logging mechanism .


public function connectTypeToStrategy($type, $strategy)
    {
        if (!is_string($type)) {
            /**
             * @see Zend_Soap_Wsdl_Exception
             */
            require_once "Zend/Soap/Wsdl/Exception.php";
            throw new Zend_Soap_Wsdl_Exception("Invalid type given to Composite Type Map.");
        }
        $this->_typeMap[$type] = $strategy;
        return $this;
    }

/**
             * @see Zend_Soap_Wsdl_Exception
             */

Connect a complex type to a given strategy.

@throws Zend_Soap_Wsdl_Exception
@param  string $type
@param  string|Zend_Soap_Wsdl_Strategy_Interface $strategy
@return Zend_Soap_Wsdl_Strategy_Composite

Connect a complex type to a given strategy .


public function getDefaultStrategy()
    {
        $strategy = $this->_defaultStrategy;
        if (is_string($strategy) && class_exists($strategy)) {
            $strategy = new $strategy;
        }
        if (!($strategy instanceof Zend_Soap_Wsdl_Strategy_Interface)) {
            /**
             * @see Zend_Soap_Wsdl_Exception
             */
            require_once "Zend/Soap/Wsdl/Exception.php";
            throw new Zend_Soap_Wsdl_Exception(
                "Default Strategy for Complex Types is not a valid strategy object."
            );
        }
        $this->_defaultStrategy = $strategy;
        return $strategy;
    }

Return default strategy of this composite

@throws Zend_Soap_Wsdl_Exception
@param  string $type
@return Zend_Soap_Wsdl_Strategy_Interface


public function getStrategyOfType($type)
    {
        if (isset($this->_typeMap[$type])) {
            $strategy = $this->_typeMap[$type];

            if (is_string($strategy) && class_exists($strategy)) {
                $strategy = new $strategy();
            }

            if (!($strategy instanceof Zend_Soap_Wsdl_Strategy_Interface)) {
                /**
                 * @see Zend_Soap_Wsdl_Exception
                 */
                require_once "Zend/Soap/Wsdl/Exception.php";
                throw new Zend_Soap_Wsdl_Exception(
                    "Strategy for Complex Type '".$type."' is not a valid strategy object."
                );
            }
            $this->_typeMap[$type] = $strategy;
        } else {
            $strategy = $this->getDefaultStrategy();
        }
        return $strategy;
    }

/**
                 * @see Zend_Soap_Wsdl_Exception
                 */

Return specific strategy or the default strategy of this type.

@throws Zend_Soap_Wsdl_Exception
@param  string $type
@return Zend_Soap_Wsdl_Strategy_Interface

Return specific strategy or the default strategy of this type .


public function addComplexType($type)
    {
        if (!($this->_context instanceof Zend_Soap_Wsdl)) {
            /**
             * @see Zend_Soap_Wsdl_Exception
             */
            require_once "Zend/Soap/Wsdl/Exception.php";
            throw new Zend_Soap_Wsdl_Exception(
                "Cannot add complex type '".$type."', no context is set for this composite strategy."
            );
        }

        $strategy = $this->getStrategyOfType($type);
        $strategy->setContext($this->_context);
        return $strategy->addComplexType($type);
    }

Create a complex type based on a strategy

@throws Zend_Soap_Wsdl_Exception
@param  string $type
@return string XSD type


private function makeReflection()
    {
        if (!class_exists($this->getOriginalClassName())) {
            throw new InvalidArgumentException('Class name ' . $this->getOriginalClassName() . ' not exists');
        }

        $this->reflection = new ReflectionClass($this->getOriginalClassName());
    }

private
function
makeReflection
(
)
{
if
(
!
class_exists
(
$
this
->
getOriginalClassName
(
)
)
)
{
throw
new
InvalidArgumentException
(
'Class name '
.
$
this
->
getOriginalClassName
(
)
.
' not exists'
)
;
}
$
this
->
reflection
=
new
ReflectionClass
(
$
this
->
getOriginalClassName
(
)
)
;
}

Create reflection based on class name
@throws InvalidArgumentException


private function populatePropertyComments()
    {
        if (is_null($this->properties)) {
            throw new UnexpectedValueException('Properties are expected here');
        }

        if (!is_array($this->properties)) {
            throw new UnexpectedValueException('Properties should be provided as array');
        }
        // if nothing to do here
        if (is_array($this->properties) && empty($this->properties)) {
            return null;
        }

        $extractor = new MetadataExtractor();
        $this->model = $extractor->processComments($this->properties);
    }

Collect comments for defined properties. It will be used to extract meta data
@return mixed
@throws UnexpectedValueException

Collect comments for defined properties . It will be used to extract meta data


private function forgeInstance($instance)
    {
        $reflection = new ReflectionClass($instance);
        foreach ($reflection->getProperties() as $key => $property) {
            if (!$property instanceof ReflectionProperty) {
                continue;
            }
            $entity = $this->getEntityFromModel($key, $property->getName());
            $value = $property->getValue($instance);

            if (is_array($value)) {
                $this->processPropertyValues($instance, $property, $entity, $value);
            } else {
                $this->processPropertyValue($instance, $property, $entity, $value);
            }
        }
        return $instance;
    }

private function forgeInstance ( $ instance ) { $ reflection = new ReflectionClass ( $ instance ) ; foreach ( $ reflection -> getProperties ( ) as $ key => $ property ) { if ( ! $ property instanceof ReflectionProperty ) { continue ; } $ entity = $ this -> getEntityFromModel ( $ key , $ property -> getName ( ) ) ; $ value = $ property -> getValue ( $ instance ) ; if ( is_array ( $ value ) ) { $ this -> processPropertyValues ( $ instance , $ property , $ entity , $ value ) ; } else { $ this -> processPropertyValue ( $ instance , $ property , $ entity , $ value ) ; } } return $ instance ; }

Creates new instance of target class with specified values
It also adjusts any nested type based on suplied metadata (@var annotation)
@return mixed returns domain model instance