private function processPropertyValues($instance, $property, $model, $values)
    {
        $changed = false;

        foreach ($values as &$value) {
            if (!$this->isMorhing($model, $value)) {
                continue;
            }
            $newType = $model->getType();
            //$value = new $newType( (array) $value );
            $value = static::create($newType, (array) $value);
            $changed = true;
        }
        if ($changed) {
            $property->setValue($instance, $values);
        }
    }

Converts object values into domain model entities.
This function is array-compatible version of @see processPropertyValue
@param mixed $instance - contains empty of almost ready domain model entity
@param ReflectionProperty $property
@param AbstractEntity $model
@param array stdClass $values

Converts object values into domain model entities . This function is array - compatible version of


public static function create($type, $values)
    {
        $i = new static($type);
        $i->usePropertyValues($values);
        return $i->createInstance();
    }

public static function create ( $ type , $ values ) { $ i = new static ( $ type ) ; $ i -> usePropertyValues ( $ values ) ; return $ i -> createInstance ( ) ; }

Creates instance of specified type and returns it as result.

@param string $type
@param array $values
@return mixed

Creates instance of specified type and returns it as result .


private function isMorhing($entity, $value)
    {
        if (!$entity instanceof ObjectEntity) {
            return false;
        }
       //String, numeric are fine
       if (!is_object($value)) {
           return false;
       }
       // if object has same type already (it's wierd, but ok)
       if (get_class($value) === $entity->getType()) {
           return false;
       }
       // we expect stdClass here only
       if (!$value instanceof \stdClass) {
           return false;
       }
        return true;
    }

Returns true if value can be converted into domain model instance
@param AbstractEntity $entity
@param \stdClass $value
@return boolean


private function processPropertyValue($instance, $property, $model, $value)
    {
        if ($this->isMorhing($model, $value)) {
            $newType = $model->getType();
            $new = static::create($newType, (array) $value);
            $property->setValue($instance, $new);
        }
    }

private function processPropertyValue ( $ instance , $ property , $ model , $ value ) { if ( $ this -> isMorhing ( $ model , $ value ) ) { $ newType = $ model -> getType ( ) ; $ new = static :: create ( $ newType , ( array ) $ value ) ; $ property -> setValue ( $ instance , $ new ) ; } }

Converts value into domain model object
@param mixed $instance - contains empty of almost ready domain model entity
@param ReflectionProperty $property
@param AbstractEntity $model
@param \stdClass $value


private function getEntityFromModel($index, $propertyName)
    {
        $entity = $this->model[$index];
        if ($entity->getName() === $propertyName) {
            return $entity;
        }
        // TODO Do we need to implement search by name in model?
        throw new RuntimeException("Unexpected $propertyName by the given index.");
    }

Returns metadata description of property from model

@param string $index
@param string $propertyName
@return AbstractEntity
@throws RuntimeException


public function updateServiceContextSettingsForOthers($serviceContext)
    {
        $this->setupServiceContext($serviceContext);
        $this->setupSerializers();
        $this->useMinorVersion();
        $this->setupRestHandler($serviceContext);
    }

public function updateServiceContextSettingsForOthers ( $ serviceContext ) { $ this -> setupServiceContext ( $ serviceContext ) ; $ this -> setupSerializers ( ) ; $ this -> useMinorVersion ( ) ; $ this -> setupRestHandler ( $ serviceContext ) ; }

Set the corresponding settings for the dataService based on ServiceContext
@var ServiceContext $serviceContext        The service Context for this DataService


protected function setupRestHandler($serviceContext)
    {
       if(isset($serviceContext)){
          $client = ClientFactory::createClient($this->getClientName());
          $this->restHandler = new SyncRestHandler($serviceContext, $client);
       }else{
          throw new SdkException("Can not set the Rest Client based on null ServiceContext.");
       }
       return $this;
    }

Set the SyncRest Handler for the DataService. If the client Name changed, the underlying Client that SyncRestHandler used will also changed.

@var ServiceContext $serviceContext         The service Context for this DataService
@return $this

Set the SyncRest Handler for the DataService . If the client Name changed the underlying Client that SyncRestHandler used will also changed .


public function setLogLocation($new_log_location)
    {
        $restHandler = $this->restHandler;
        $loggerUsedByRestHandler = $restHandler->getRequestLogger();
        $loggerUsedByRestHandler->setLogDirectory($new_log_location);
        return $this;
    }

public function setLogLocation ( $ new_log_location ) { $ restHandler = $ this -> restHandler ; $ loggerUsedByRestHandler = $ restHandler -> getRequestLogger ( ) ; $ loggerUsedByRestHandler -> setLogDirectory ( $ new_log_location ) ; return $ this ; }

Set a new directory for request and response log

@param String $new_log_location     The directory path for storing request and response log

@return $this


public function setMinorVersion($newMinorVersion)
    {
        $serviceContext = $this->getServiceContext();
        $serviceContext->setMinorVersion($newMinorVersion);
        $this->updateServiceContextSettingsForOthers($serviceContext);
        return $this;
    }

public function setMinorVersion ( $ newMinorVersion ) { $ serviceContext = $ this -> getServiceContext ( ) ; $ serviceContext -> setMinorVersion ( $ newMinorVersion ) ; $ this -> updateServiceContextSettingsForOthers ( $ serviceContext ) ; return $ this ; }

Set a new Minor Version

@param String $newMinorVersion     The new minor version that passed

@return $this


public function disableLog()
    {
        $restHandler = $this->restHandler;
        $loggerUsedByRestHandler = $restHandler->getRequestLogger();
        $loggerUsedByRestHandler->setLogStatus(false);
        return $this;
    }

public function disableLog ( ) { $ restHandler = $ this -> restHandler ; $ loggerUsedByRestHandler = $ restHandler -> getRequestLogger ( ) ; $ loggerUsedByRestHandler -> setLogStatus ( false ) ; return $ this ; }

Disable the logging function

@return $this


public function enableLog()
    {
        $restHandler = $this->restHandler;
        $loggerUsedByRestHandler = $restHandler->getRequestLogger();
        $loggerUsedByRestHandler->setLogStatus(true);
        return $this;
    }

public function enableLog ( ) { $ restHandler = $ this -> restHandler ; $ loggerUsedByRestHandler = $ restHandler -> getRequestLogger ( ) ; $ loggerUsedByRestHandler -> setLogStatus ( true ) ; return $ this ; }

Enable the logging function

@return $this


public function setClientName($clientName){
       $this->clientName = $clientName;
       $serviceContext = $this->getServiceContext();
       $this->setupRestHandler($serviceContext);
       return $this;
    }

public function setClientName ( $ clientName ) { $ this -> clientName = $ clientName ; $ serviceContext = $ this -> getServiceContext ( ) ; $ this -> setupRestHandler ( $ serviceContext ) ; return $ this ; }

The client Name can be either 'curl', 'guzzle', or 'guzzlehttp'.

@param String $clientName              The client Name used by the service

@return $this

The client Name can be either curl guzzle or guzzlehttp .


public static function Configure($settings)
    {
        if (isset($settings)) {
            if (is_array($settings)) {
                $ServiceContext = ServiceContext::ConfigureFromPassedArray($settings);
                if (!isset($ServiceContext)) {
                    throw new SdkException('Construct ServiceContext from OAuthSettigs failed.');
                }
                $DataServiceInstance = new DataService($ServiceContext);

            } elseif (is_string($settings)) {
                $ServiceContext = ServiceContext::ConfigureFromLocalFile($settings);
                if (!isset($ServiceContext)) {
                    throw new SdkException('Construct ServiceContext from File failed.');
                }
                $DataServiceInstance = new DataService($ServiceContext);

            }

            if($ServiceContext->IppConfiguration->OAuthMode == CoreConstants::OAUTH2)
            {
                $oauth2Config = $ServiceContext->IppConfiguration->Security;
                if($oauth2Config instanceof OAuth2AccessToken){
                    $DataServiceInstance->configureOAuth2LoginHelper($oauth2Config, $settings);
                }else{
                    throw new SdkException("SDK Error. OAuth mode is not OAuth 2.");
                }
            }

            return $DataServiceInstance;

        } else {
            throw new SdkException("Passed Null to Configure method. It expects either a file path for the config file or an array containing OAuth settings and BaseURL.");
        }
    }

New Static function for static Reading from Config or Passing Array
The config needs to include

@param $settings
@return DataService
@throws SdkException
@throws SdkException


private function configureOAuth2LoginHelper($oauth2Conifg, $settings)
    {
          $refreshToken = CoreConstants::getRefreshTokenFromArray($settings);
          if(isset($refreshToken)){
               //Login helper for refresh token API call
               $this->OAuth2LoginHelper = new OAuth2LoginHelper(null,
                                                                null,
                                                                null,
                                                                null,
                                                                null,
                                                                $this->getServiceContext());
          }else{
                $redirectURL = CoreConstants::getRedirectURL($settings);
                $scope = array_key_exists('scope', $settings) ? $settings['scope'] : null;
                $state = array_key_exists('state', $settings) ? $settings['state'] : null;
                $this->OAuth2LoginHelper = new OAuth2LoginHelper($oauth2Conifg->getClientID(),
                                                                 $oauth2Conifg->getClientSecret(),
                                                                 $redirectURL,
                                                                 $scope,
                                                                 $state);
          }
    }

After the ServiceContext is complete, also set the LoginHelper based on the ServiceContext.
@param OAuth2AccessToken $oauth2Conifg      OAuth 2 Token related information
@param Array $settings                      The array that include the redirectURL, scope, state information

After the ServiceContext is complete also set the LoginHelper based on the ServiceContext .


public function updateOAuth2Token($newOAuth2AccessToken)
    {
        try{
          $this->serviceContext->updateOAuth2Token($newOAuth2AccessToken);
          $realmID = $newOAuth2AccessToken->getRealmID();
          $this->serviceContext->realmId = $realmID;
          $this->setupRestHandler($this->serviceContext);
        } catch (SdkException $e){
            $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "Encountered an error while updating OAuth2Token." . $e->getMessage());
            $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "Stack Trace: " . $e->getTraceAsString());
        }
        return $this;
    }

Update the OAuth 2 Token that will be used for API calls later.

@param OAuth2AccessToken $newOAuth2AccessToken   The OAuth 2 Access Token that will be used later.

@return $this

Update the OAuth 2 Token that will be used for API calls later .


public function setupSerializers()
    {
        $this->responseSerializer = CoreHelper::GetSerializer($this->serviceContext, false);
        $this->requestSerializer = CoreHelper::GetSerializer($this->serviceContext, true);
    }

public function setupSerializers ( ) { $ this -> responseSerializer = CoreHelper :: GetSerializer ( $ this -> serviceContext , false ) ; $ this -> requestSerializer = CoreHelper :: GetSerializer ( $ this -> serviceContext , true ) ; }

Setups serializers objects for responces and requests based on service context


public function Update($entity)
    {
        $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method: Update.");

        // Validate parameter
        if (!$entity) {
            $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception");
            throw new IdsException('Argument Null Exception');
        }
        $this->verifyOperationAccess($entity, __FUNCTION__);

        $httpsPostBody = $this->executeObjectSerializer($entity, $urlResource);

        // Builds resource Uri
        // Handle some special cases
        if ((strtolower('preferences') == strtolower($urlResource)) &&
            (CoreConstants::IntuitServicesTypeQBO == $this->serviceContext->serviceType)
        ) {
            // URL format for *QBO* prefs request is different than URL format for *QBD* prefs request
            $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource));
        }
        //We no longer support QBD on PHP SDK The code is removed.
        /*else if ((strtolower('company') == strtolower($urlResource)) &&
                (CoreConstants::IntuitServicesTypeQBO == $this->serviceContext->serviceType)) {
            // URL format for *QBD* companyinfo request is different than URL format for *QBO* companyinfo request
            $urlResource = 'companyInfo';
            $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource . '?operation=update'));
        }*/ else {
            // Normal case
            $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource . '?operation=update'));
        }

        // Send Request and return response
        return $this->sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, $httpsPostBody, DataService::UPDATE);
    }

Updates an entity under the specified realm. The realm must be set in the context.

@param IPPIntuitEntity $entity Entity to Update.
@return IPPIntuitEntity Returns an updated version of the entity with updated identifier and sync token.
@throws IdsException

Updates an entity under the specified realm . The realm must be set in the context .


public function Add($entity)
    {
        $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Add.");

        // Validate parameter
        if (!$entity) {
            $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception");
            throw new IdsException('Argument Null Exception');
        }
        $this->verifyOperationAccess($entity, __FUNCTION__);
        if ($this->isJsonOnly($entity)) {
            $this->forceJsonSerializers();
        }
        $httpsPostBody = $this->executeObjectSerializer($entity, $urlResource);

        // Builds resource Uri
        $resourceURI = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource));

        $uri = $this->handleTaxService($entity, $resourceURI);

        // Send request
        return $this->sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, $httpsPostBody, DataService::ADD);
    }

Creates an entity under the specified realm. The realm must be set in the context.

@param IPPIntuitEntity $entity Entity to Create.
@return IPPIntuitEntity Returns the created version of the entity.
@throws IdsException

Creates an entity under the specified realm . The realm must be set in the context .


public function Delete($entity)
    {
        $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Delete.");

        // Validate parameter
        if (!$entity) {
            $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception");
            throw new IdsException('Argument Null Exception');
        }
        $this->verifyOperationAccess($entity, __FUNCTION__);

        // Builds resource Uri
        $httpsPostBody = $this->executeObjectSerializer($entity, $urlResource);
        $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource . '?operation=delete'));

        // Creates request
        return $this->sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, $httpsPostBody, DataService::DELETE);
    }

Deletes an entity under the specified realm. The realm must be set in the context.

@param IPPIntuitEntity $entity Entity to Delete.
@return null|string
@throws IdsException

Deletes an entity under the specified realm . The realm must be set in the context .


public function Upload($imgBits, $fileName, $mimeType, $objAttachable)
    {
        $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Upload.");

        // Validate parameter
        if (!$imgBits || !$mimeType || !$fileName) {
            $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception");
            throw new IdsException('Argument Null Exception');
        }
        // Builds resource Uri
        $urlResource = "upload";
        $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource));

        $boundaryString = md5(time());

        $MetaData = $this->executeObjectSerializer($objAttachable, $urlResource);

        $desiredIdentifier = '0';
        $newline = "\r\n";
        $dataMultipart = '';
        $dataMultipart .= '--' . $boundaryString . $newline;
        $dataMultipart .= "Content-Disposition: form-data; name=\"file_metadata_{$desiredIdentifier}\"" . $newline;
        $dataMultipart .= "Content-Type: " . CoreConstants::CONTENTTYPE_APPLICATIONXML . '; charset=UTF-8' . $newline;
        $dataMultipart .= 'Content-Transfer-Encoding: 8bit' . $newline . $newline;
        $dataMultipart .= $MetaData;
        $dataMultipart .= '--' . $boundaryString . $newline;
        $dataMultipart .= "Content-Disposition: form-data; name=\"file_content_{$desiredIdentifier}\"; filename=\"{$fileName}\"" . $newline;
        $dataMultipart .= "Content-Type: {$mimeType}" . $newline;
        $dataMultipart .= 'Content-Transfer-Encoding: base64' . $newline . $newline;
        $dataMultipart .= chunk_split(base64_encode($imgBits)) . $newline;
        $dataMultipart .= "--" . $boundaryString . "--" . $newline . $newline; // finish with two eol's!!

        return $this->sendRequestParseResponseBodyAndHandleHttpError(null, $uri, $dataMultipart, DataService::UPLOAD, $boundaryString);
    }

Uploads an attachment to an Entity on QuickBooks Online. For security reason, text file is not supported for uploading.

@param string $bits                        Encoded Base64 bytes for the attachment
@param string $fileName                    Filename to use for this file
@param string $mimeType                    MIME type to send in the HTTP Headers
@param IPPAttachable $objAttachable        Entity including the attachment, it can be invoice, bill, etc
@return array                              Returns an array of entities fulfilling the query.
@throws IdsException

Uploads an attachment to an Entity on QuickBooks Online . For security reason text file is not supported for uploading .


public function SendEmail($entity, $email = null)
    {
        $this->validateEntityId($entity);
        $this->verifyOperationAccess($entity, __FUNCTION__);

        $entityId=$this->getIDString($entity->Id);
        $uri = implode(CoreConstants::SLASH_CHAR, array('company',
                $this->serviceContext->realmId,
                self::getEntityResourceName($entity),
                $entityId,
                'send'));

        if (is_null($email)) {
            $this->logInfo("Entity " . get_class($entity) . " with id=" . $entityId . " is using default email");
        } else {
            $this->logInfo("Entity " . get_class($entity) . " with id=" . $entityId . " is using $email");
            if (!$this->verifyEmailAddress($email)) {
                $this->logError("Valid email is expected, but received $email");
                throw new SdkException("Valid email is expected, but received $email");
            }
        }

        return $this->sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, null, DataService::SENDEMAIL, null, $email);
    }

Sends entity by email for entities that have this operation

@param IPPIntuitEntity $entity
@param string|null $email
@return boolean
@throws IdsException, SdkException


public function Query($query, $startPosition = null, $maxResults = null)
    {
        $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Query.");

        if ('QBO' == $this->serviceContext->serviceType) {
            $httpsContentType = CoreConstants::CONTENTTYPE_APPLICATIONTEXT;
        } else {
            $httpsContentType = CoreConstants::CONTENTTYPE_TEXTPLAIN;
        }

        $httpsUri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, 'query'));
        $httpsPostBody = $this->appendPaginationInfo($query, $startPosition, $maxResults);

        $requestParameters = $this->getPostRequestParameters($httpsUri, $httpsContentType);
        $restRequestHandler = $this->getRestHandler();
        list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, $httpsPostBody, null, $this->isThrownExceptionOnError());
        $faultHandler = $restRequestHandler->getFaultHandler();
        if ($faultHandler) {
            $this->lastError = $faultHandler;
            return null;
        } else {
            $this->lastError = false;
            $parsedResponseBody = null;
            try {
                $responseXmlObj = simplexml_load_string($responseBody);
                if ($responseXmlObj && $responseXmlObj->QueryResponse) {
                    $tmpXML = $responseXmlObj->QueryResponse->asXML();
                }
                $parsedResponseBody = $this->responseSerializer->Deserialize($tmpXML, false);
                $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, $parsedResponseBody);

            } catch (\Exception $e) {
                throw new \Exception("Exception appears in converting Response to XML.");
            }

            return $parsedResponseBody;
        }
    }

Retrieves specified entities based passed page number and page size and query

@param string $query Query to issue
@param int $startPosition Starting page number
@param int $maxResults Page size
@return array Returns an array of entities fulfilling the query. If the response is Empty, it will return NULL


private function appendPaginationInfo($query, $startPosition, $maxResults){
       $query = trim($query);
       if(isset($startPosition) && !empty($startPosition)){
           if(stripos($query, "STARTPOSITION") === false){
              if(stripos($query, "MAXRESULTS") !== false){
                //In MaxResult is defined,we don't set startPosition
              }else{
                $query = $query . " " . "STARTPOSITION " . $startPosition;
              }
           }else{
             //Ignore the startPosition if it is already used on the query
           }
       }

       if(isset($maxResults) && !empty($maxResults)){
           if(stripos($query, "MAXRESULTS") === false){
                $query = $query . " " . "MAXRESULTS " . $maxResults;
           }else{
             //Ignore the maxResults if it is already used on the query
           }
       }

       return $query;

    }

Append the Pagination Data to the Query string if it is not appended
@param Integer StartPostion
@param Integer MaxResults
@return String The query string


public function FindAll($entityName, $pageNumber = 0, $pageSize = 500)
    {
        $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method FindAll.");

        $phpClassName = DataService::decorateIntuitEntityToPhpClassName($entityName);

        // Handle some special cases
        if (strtolower('company') == strtolower($entityName)) {
            $entityName = 'CompanyInfo';
        }

        if ('QBO' == $this->serviceContext->serviceType) {
            $httpsContentType = CoreConstants::CONTENTTYPE_APPLICATIONTEXT;
        } else {
            $httpsContentType = CoreConstants::CONTENTTYPE_TEXTPLAIN;
        }

        $httpsUri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, 'query'));
        $httpsPostBody = "select * from $entityName startPosition $pageNumber maxResults $pageSize";

        $requestParameters = $this->getPostRequestParameters($httpsUri, $httpsContentType);
        $restRequestHandler = $this->getRestHandler();
        list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, $httpsPostBody, null, $this->isThrownExceptionOnError());
        $faultHandler = $restRequestHandler->getFaultHandler();
        if ($faultHandler) {
            $this->lastError = $faultHandler;
            return null;
        } else {
            $this->lastError = false;
            $parsedResponseBody = null;
            try {
                $responseXmlObj = simplexml_load_string($responseBody);
                if ($responseXmlObj && $responseXmlObj->QueryResponse) {
                    $parsedResponseBody = $this->responseSerializer->Deserialize($responseXmlObj->QueryResponse->asXML(), false);
                }
            } catch (\Exception $e) {
                throw new \Exception("Exception appears in converting Response to XML.");
            }

            return $parsedResponseBody;
        }
    }

Retrieves all entities by name

@param string $entityName
@param int $pageNumber
@param int $pageSize
@return array Returns an array of entities of specified type.


public function CDC($entityList, $changedSince)
    {
        $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, "Called Method CDC.");

        // Validate parameter
        if (count($entityList) <= 0) {
            $exception = new IdsException('ParameterNotNullMessage');
            $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "ParameterNotNullMessage");
            IdsExceptionManager::HandleException($exception);
        }

        $entityString = implode(",", $entityList);

        $query = null;
        $uri = null;

        if(is_string($changedSince)){
           $formattedChangedSince = trim($changedSince);
        }else{
            $formattedChangedSince = date("Y-m-d\TH:i:s", $this->verifyChangedSince($changedSince));
        }

        $query = "entities=" . $entityString . "&changedSince=" . $formattedChangedSince;
        $uri = "company/{1}/cdc?{2}";
        //$uri = str_replace("{0}", CoreConstants::VERSION, $uri);
        $uri = str_replace("{1}", $this->serviceContext->realmId, $uri);
        $uri = str_replace("{2}", $query, $uri);

        // Creates request parameters
        $requestParameters = $this->getGetRequestParameters($uri, CoreConstants::CONTENTTYPE_APPLICATIONXML);
        $restRequestHandler = $this->getRestHandler();

        list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, null, null, $this->isThrownExceptionOnError());
        $faultHandler = $restRequestHandler->getFaultHandler();
        if ($faultHandler) {
            $this->lastError = $faultHandler;
            return null;
        } else {
            $this->lastError = false;
            $returnValue = new IntuitCDCResponse();
            try {
                $xmlObj = simplexml_load_string($responseBody);
                $responseArray = $xmlObj->CDCResponse->QueryResponse;
                if(sizeof($responseArray) != sizeof($entityList)){
                    throw new ServiceException("The number of Entities requested on CDC does not match the number of Response.");
                }

                for($i = 0; $i < sizeof($responseArray); $i++){
                    $currentResponse = $responseArray[$i];
                    $currentEntityName = $entityList[$i];
                    $entities = $this->responseSerializer->Deserialize($currentResponse->asXML(), false);
                    $entityName = $currentEntityName;
                    //If we find the actual name, update it.
                    foreach ($currentResponse->children() as $currentResponseChild) {
                        $entityName = (string)$currentResponseChild->getName();
                        break;
                    }
                    $returnValue->entities[$entityName] = $entities;
                }
            } catch (\Exception $e) {
                IdsExceptionManager::HandleException($e);
            }

            $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, "Finished Executing Method CDC.");
            return $returnValue;
        }
    }

Returns List of entities changed after certain time.

@param array entityList List of entity.
@param long changedSince DateTime of timespan after which entities were changed.
@return IntuitCDCResponse Returns an IntuitCDCResponse.

Returns List of entities changed after certain time .


protected function executeObjectSerializer($entity, &$urlResource)
    {
        //
        $result = $this->getRequestSerializer()->Serialize($entity);
        $urlResource = $this->getRequestSerializer()->getResourceURL();

        return $result;
    }

protected function executeObjectSerializer ( $ entity , & $ urlResource ) { // $ result = $ this -> getRequestSerializer ( ) -> Serialize ( $ entity ) ; $ urlResource = $ this -> getRequestSerializer ( ) -> getResourceURL ( ) ; return $ result ; }

Serializes oblect into specified format
@param IPPIntuitEntity $entity
@param String $urlResource
@return object


protected function initPostRequest($entity, $uri)
    {
        return $this->isJsonOnly($entity)
            ? $this->getPostJsonRequest($uri)
            : $this->getPostRequest($uri);
    }

protected function initPostRequest ( $ entity , $ uri ) { return $ this -> isJsonOnly ( $ entity ) ? $ this -> getPostJsonRequest ( $ uri ) : $ this -> getPostRequest ( $ uri ) ; }

Returns post request, depends on configuration and entity rule "jsonOnly"
@param IPPIntuitEntity $entity
@param string $uri
@return RequestParameters

Returns post request depends on configuration and entity rule jsonOnly


protected function getRequestParameters($uri, $method, $type, $apiName = null)
    {
        return new RequestParameters($uri, $method, $type, $apiName);
    }

protected function getRequestParameters ( $ uri , $ method , $ type , $ apiName = null ) { return new RequestParameters ( $ uri , $ method , $ type , $ apiName ) ; }

Wraps and returns RequestParameters object
@param string $uri
@param string $method
@param string $type
@param string $apiName
@return RequestParameters


private function fixTaxServicePayload($entity, $content)
    {
        if ($this->isTaxServiceSafe($entity)) {
            //get first "line" to make sure we don't have TaxService in response
            $sample = substr(trim($content), 0, 20);
            $taxServiceName = self::cleanPhpClassNameToIntuitEntityName(get_class($entity));
            if (false === strpos($sample, $taxServiceName)) {
                //last attempt to verify content before
                if (0 === strpos($sample, '{"TaxCode":')) {
                    return "{\"$taxServiceName\":$content}";
                }
            }
        }

        return $content;
    }

Methods provides workaround to successfully process TaxService response
@param $entity
@param $content
@return string


public function getExportFileNameForPDF($entity, $ext, $usetimestamp = true)
    {
        //TODO: add timestamp or GUID
        $this->validateEntityId($entity);

        return self::getEntityResourceName($entity) . "_" . $this->getIDString($entity->Id) . ($usetimestamp ? "_" . time() : "") . ".$ext";
    }

public
function
getExportFileNameForPDF
(
$
entity
,
$
ext
,
$
usetimestamp
=
true
)
{
//TODO: add timestamp or GUID
$
this
->
validateEntityId
(
$
entity
)
;
return
self
::
getEntityResourceName
(
$
entity
)
.
"_"
.
$
this
->
getIDString
(
$
entity
->
Id
)
.
(
$
usetimestamp
"_"
.
time
(
)
:
""
)
.
".$ext"
;
}

Returns PDF filename based on entity type and id
@param IPPIntuitEntity $entity
@param string $ext
@return string


private function isAllowed($entity, $method)
    {
        $className = get_class($entity);
        if (!$className) {
            $this->logError("Intuit entity is expected here instead of $entity");
            throw new IdsException('Unexpected Argument Exception');
        }

        $classArray = explode('\\', $className);
        $trimedClassName = end($classArray);

        return $this->serviceContext->IppConfiguration->OpControlList->isAllowed($trimedClassName, $method);
    }

Simple verification for entities which can be returned as PDF


public function CreateNewBatch()
    {
        $batch = new Batch($this->serviceContext, $this->getRestHandler(), $this->isThrownExceptionOnError());

        return $batch;
    }

public function CreateNewBatch ( ) { $ batch = new Batch ( $ this -> serviceContext , $ this -> getRestHandler ( ) , $ this -> isThrownExceptionOnError ( ) ) ; return $ batch ; }

Creates new batch

@return Batch returns the batch object


private function convertToTimestamp($str)
    {
        $result = date_parse($str);
        if (!$result) {
            return false;
        }
        if (empty($result) || !is_array($result)) {
            return false;
        }
        extract($result);
        if (!empty($errors)) {
            throw new SdkException("SDK failed to parse date value \"$str\":"
                . (is_array($errors) ? implode("\n", $errors) : $errors)
            );
        }

        //@TODO: mktime is deprecated since 5.3.0, this package needs 5.6
        return mktime($hour, $minute, $second, $month, $day, $year);
    }

Parse input date-time string into unix timestamp
@param string $str
@return int timestamp or false overwise
@throws SdkException

Parse input date - time string into unix timestamp


public function isValidTimeStamp($timestamp)
    {
        return ((string)(int)$timestamp === $timestamp) && ($timestamp <= PHP_INT_MAX) && ($timestamp >= ~PHP_INT_MAX);
    }

public function isValidTimeStamp ( $ timestamp ) { return ( ( string ) ( int ) $ timestamp === $ timestamp ) && ( $ timestamp <= PHP_INT_MAX ) && ( $ timestamp >= ~ PHP_INT_MAX ) ; }

Checks if input string is a valid timestamp or not
@param string timestamp contains input timestamp-like string
@return bool


protected function verifyChangedSince($value)
    {
        if (is_int($value)) {
            return $value;
        }
        // remove whitespaces, tabulation etc
        $trimmed = trim($value);
        if ($this->isValidTimeStamp($trimmed)) {
            return $trimmed;
        }
        //at this point we have numeric string which is not timestamp
        if (is_numeric($value)) {
            throw new SdkException("Input string doesn't look as unix timestamp or date string");
        }
        // trying to parse string into timestamp
        $converted = $this->convertToTimestamp($value);
        if (!$converted) {
            throw new SdkException("Input value should be unix timestamp or valid date string");
        }

        return $converted;
    }

Verifies input and returns unix timestamp
@param mixed $value
@return int
@throws SdkException


public function getCompanyInfo()
    {
        $currentServiceContext = $this->getServiceContext();
        if (!isset($currentServiceContext) || empty($currentServiceContext->realmId)) {
            throw new SdkException("Please Setup Service Context before making get CompanyInfo call.");
        }
        //The CompanyInfo URL
        $uri = implode(CoreConstants::SLASH_CHAR, array('company', $currentServiceContext->realmId, 'companyinfo', $currentServiceContext->realmId));
        $requestParameters = new RequestParameters($uri, 'GET', CoreConstants::CONTENTTYPE_APPLICATIONXML, null);
        $restRequestHandler = $this->getRestHandler();
        list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, null, null, $this->isThrownExceptionOnError());
        $faultHandler = $restRequestHandler->getFaultHandler();
        //$faultHandler now is true or false
        if ($faultHandler) {
            $this->lastError = $faultHandler;
            return null;
        } else {
            $this->lastError = false;
            $parsedResponseBody = $this->getResponseSerializer()->Deserialize($responseBody, true);
            return $parsedResponseBody;
        }
    }

Get the Company Information
@return IPPCompanyInfo   CompanyInformation


public static function getQuickBooksOnlineAPIEntityRules()
    {
        return
                         array(
                                    '*'               => array(
                                                                "DownloadPDF" => false,
                                                                "jsonOnly" => false,
                                                                "SendEmail"=> false),
                                    "IPPTaxService"   => array( '*' => false,
                                                                'Add' => true,
                                                                'jsonOnly' => true),
                                    "IPPSalesReceipt" => array( "DownloadPDF" => true, "SendEmail" => true ),
                                    "IPPInvoice"      => array( "DownloadPDF" => true, "SendEmail" => true  ),
                                    "IPPEstimate"     => array( "DownloadPDF" => true, "SendEmail" => true  ),
                            );
    }

public static function getQuickBooksOnlineAPIEntityRules ( ) { return array ( '*' => array ( "DownloadPDF" => false , "jsonOnly" => false , "SendEmail" => false ) , "IPPTaxService" => array ( '*' => false , 'Add' => true , 'jsonOnly' => true ) , "IPPSalesReceipt" => array ( "DownloadPDF" => true , "SendEmail" => true ) , "IPPInvoice" => array ( "DownloadPDF" => true , "SendEmail" => true ) , "IPPEstimate" => array ( "DownloadPDF" => true , "SendEmail" => true ) , ) ; }

Returns current rules for what operation is supported and what is not for QuickBooks Online API entity
@return array


public static function getAccessTokenFromArray(array $settings){
        if(array_key_exists('accessTokenKey', $settings)){
            return $settings['accessTokenKey'];
        }else if(array_key_exists('accessToken', $settings)){
            return $settings['accessToken'];
        } else if(array_key_exists('AccessToken', $settings)){
            return $settings['AccessToken'];
        } else{
            return null;
        }
    }

public static function getAccessTokenFromArray ( array $ settings ) { if ( array_key_exists ( 'accessTokenKey' , $ settings ) ) { return $ settings [ 'accessTokenKey' ] ; } else if ( array_key_exists ( 'accessToken' , $ settings ) ) { return $ settings [ 'accessToken' ] ; } else if ( array_key_exists ( 'AccessToken' , $ settings ) ) { return $ settings [ 'AccessToken' ] ; } else { return null ; } }

A helper method to get Access Token Key. People may have a typo on the key name
@param Array $settings     The array contains all the key values
@return String | null      The access token developer provided

A helper method to get Access Token Key . People may have a typo on the key name


public static function getRefreshTokenFromArray(array $settings){
        if(array_key_exists('refreshTokenKey', $settings)){
            return $settings['refreshTokenKey'];
        }else if(array_key_exists('refreshToken', $settings)){
            return $settings['refreshToken'];
        } else if(array_key_exists('RefreshToken', $settings)){
            return $settings['RefreshToken'];
        } else{
            return null;
        }
    }

public static function getRefreshTokenFromArray ( array $ settings ) { if ( array_key_exists ( 'refreshTokenKey' , $ settings ) ) { return $ settings [ 'refreshTokenKey' ] ; } else if ( array_key_exists ( 'refreshToken' , $ settings ) ) { return $ settings [ 'refreshToken' ] ; } else if ( array_key_exists ( 'RefreshToken' , $ settings ) ) { return $ settings [ 'RefreshToken' ] ; } else { return null ; } }

A helper method to get Refresh Token Key. People may have a typo on the key name
@param Array $settings     The array contains all the key values
@return String | null      The refresh token developer provided

A helper method to get Refresh Token Key . People may have a typo on the key name


public static function getRedirectURL(array $settings){
        if(array_key_exists('redirectURL', $settings)){
            return $settings['redirectURL'];
        }else if(array_key_exists('RedirectUrl', $settings)){
            return $settings['RedirectUrl'];
        } else if(array_key_exists('redirecturl', $settings)){
            return $settings['redirecturl'];
        } else if(array_key_exists('redirectUrl', $settings)){
            return $settings['redirectUrl'];
        } else if(array_key_exists('RedirectURL', $settings)){
            return $settings['RedirectURL'];
        } else if(array_key_exists('redirectURI', $settings)){
            return $settings['redirectURI'];
        }else if(array_key_exists('RedirectUri', $settings)){
            return $settings['RedirectUri'];
        } else if(array_key_exists('redirecturi', $settings)){
            return $settings['redirecturl'];
        } else if(array_key_exists('redirectUri', $settings)){
            return $settings['redirectUrl'];
        } else if(array_key_exists('RedirectURI', $settings)){
            return $settings['RedirectURI'];
        }
        else{
            return null;
        }
    }

public static function getRedirectURL ( array $ settings ) { if ( array_key_exists ( 'redirectURL' , $ settings ) ) { return $ settings [ 'redirectURL' ] ; } else if ( array_key_exists ( 'RedirectUrl' , $ settings ) ) { return $ settings [ 'RedirectUrl' ] ; } else if ( array_key_exists ( 'redirecturl' , $ settings ) ) { return $ settings [ 'redirecturl' ] ; } else if ( array_key_exists ( 'redirectUrl' , $ settings ) ) { return $ settings [ 'redirectUrl' ] ; } else if ( array_key_exists ( 'RedirectURL' , $ settings ) ) { return $ settings [ 'RedirectURL' ] ; } else if ( array_key_exists ( 'redirectURI' , $ settings ) ) { return $ settings [ 'redirectURI' ] ; } else if ( array_key_exists ( 'RedirectUri' , $ settings ) ) { return $ settings [ 'RedirectUri' ] ; } else if ( array_key_exists ( 'redirecturi' , $ settings ) ) { return $ settings [ 'redirecturl' ] ; } else if ( array_key_exists ( 'redirectUri' , $ settings ) ) { return $ settings [ 'redirectUrl' ] ; } else if ( array_key_exists ( 'RedirectURI' , $ settings ) ) { return $ settings [ 'RedirectURI' ] ; } else { return null ; } }

A helper method to get redirect URL. People may have a typo on the key name
@param Array $settings     The array contains all the key values
@return String | null      The redirect url developer provide

A helper method to get redirect URL . People may have a typo on the key name


public function saveFile($dir, $name=null)
    {
        if (empty($dir)) {
            throw new SdkException("Directory is empty.");
        }

        if (!file_exists($dir)) {
            throw new SdkException("Directory ($dir) doesn't exist.");
        }

        if (!is_writable($dir)) {
            throw new SdkException("Directory ($dir) is not writable");
        }
        $this->tempPath = $dir . DIRECTORY_SEPARATOR . $this->generateFileName($name);
        if (file_exists($this->tempPath)) {
            throw new SdkException("File ($this->tempPath) already exists");
        }
        try {
            $result = file_put_contents($this->tempPath, $this->getContent());
        } catch (\Exception $e) {
            if (!is_writable($this->tempPath)) {
                throw new SdkException("File ({$this->tempPath}) is not writable");
            }
            throw new SdkException("Error was thrown: " . $e->getMessage() . "\File: " .$e->getFile() ." on line " . $e->getLine());
        }
        if (false === $result) {
            throw new SdkException('Unable to write content into temp file: ' . $this->tempPath);
        }
        $this->bytes = $result;
    }

Moves file from temp location to specified folder and name
@param string $dir
@param string|null $name (option) if not specified it will be moved with temp name
@throws SdkException


private function generateFileName($name)
    {
        $filename = is_null($name) ? $this->getUniqId() : $name;
        return is_null($this->getPrefix()) ? $filename : $this->getPrefix() . $filename;
    }

private function generateFileName ( $ name ) { $ filename = is_null ( $ name ) ? $ this -> getUniqId ( ) : $ name ; return is_null ( $ this -> getPrefix ( ) ) ? $ filename : $ this -> getPrefix ( ) . $ filename ; }

Creates filename based on name and prefix.
It generates uniqid-like string if name is ommited
@param string $name
@return string

Creates filename based on name and prefix . It generates uniqid - like string if name is ommited


private function generateErrorFromOAuthMsg($OAuthException)
    {
        if (get_class($OAuthException) == 'OAuthException') {
            $this->httpStatusCode = $OAuthException->getCode();
            $this->helpMsg = $OAuthException->getMessage();
            $this->responseBody = $OAuthException->lastResponse;
        } else {
            throw new \Exception("OAuthException required for generate error from Intuit. The passed parameters for Fault handler is not OAuthException");
        }
    }

generate Error from OAuth Exception
@param OAuthException  The OAuth Exception from PECL OAuth 1.2.3
@deprecated


public function parseResponse($message){
      $xmlObj = simplexml_load_string($message);

      if(!$this->isTheErrorBodyInStandardFormat($xmlObj)){
          return;
      }
      $type = (string)$xmlObj->Fault->attributes()['type'];
      if(isset($type) && !empty($type)){
        $this->intuitErrorType = $type;
      }

      $code = (string)$xmlObj->Fault->Error->attributes()['code'];
      if(isset($code) && !empty($code)){
        $this->intuitErrorCode = $code;
      }

      $element = (string)$xmlObj->Fault->Error->attributes()['element'];
      if(isset($element) && !empty($element)){
        $this->intuitErrorElement = $element;
      }

      $message = (string)$xmlObj->Fault->Error->Message;
      if(isset($message) && !empty($message)){
        $this->intuitErrorMessage = $message;
      }

      $detail = (string)$xmlObj->Fault->Error->Detail;
      if(isset($detail) && !empty($detail)){
        $this->intuitErrorDetail = $detail;
      }

    }

public function parseResponse ( $ message ) { $ xmlObj = simplexml_load_string ( $ message ) ; if ( ! $ this -> isTheErrorBodyInStandardFormat ( $ xmlObj ) ) { return ; } $ type = ( string ) $ xmlObj -> Fault -> attributes ( ) [ 'type' ] ; if ( isset ( $ type ) && ! empty ( $ type ) ) { $ this -> intuitErrorType = $ type ; } $ code = ( string ) $ xmlObj -> Fault -> Error -> attributes ( ) [ 'code' ] ; if ( isset ( $ code ) && ! empty ( $ code ) ) { $ this -> intuitErrorCode = $ code ; } $ element = ( string ) $ xmlObj -> Fault -> Error -> attributes ( ) [ 'element' ] ; if ( isset ( $ element ) && ! empty ( $ element ) ) { $ this -> intuitErrorElement = $ element ; } $ message = ( string ) $ xmlObj -> Fault -> Error -> Message ; if ( isset ( $ message ) && ! empty ( $ message ) ) { $ this -> intuitErrorMessage = $ message ; } $ detail = ( string ) $ xmlObj -> Fault -> Error -> Detail ; if ( isset ( $ detail ) && ! empty ( $ detail ) ) { $ this -> intuitErrorDetail = $ detail ; } }

Based on the HTTP Response body, set the Intuit Error elements.
@var String The http response body in XML format

Based on the HTTP Response body set the Intuit Error elements .


private function isTheErrorBodyInStandardFormat($xmlObj)
    {
        if(!isset($xmlObj->Fault) || !isset($xmlObj->Fault->Error)){
           return false;
        }
        return true;
    }

private function isTheErrorBodyInStandardFormat ( $ xmlObj ) { if ( ! isset ( $ xmlObj -> Fault ) || ! isset ( $ xmlObj -> Fault -> Error ) ) { return false ; } return true ; }

Check if the format is standard Intuit Response format. This is to prevent Intuit Return random Structured Error.
@param SimpleXMLElement the XML object of the Body
@return True | False

Check if the format is standard Intuit Response format . This is to prevent Intuit Return random Structured Error .


private function setResponseAsItIs($passedHeaders, $passedBody, $passedHttpResponseCode){
      if(isset($passedHeaders) && isset($passedBody) && isset($passedHttpResponseCode)){
          $this->headers = $passedHeaders;
          $this->body = $passedBody;
          $this->httpResponseCode = $passedHttpResponseCode;
          $this->setContentType(CoreConstants::CONTENT_TYPE, $passedHeaders[CoreConstants::CONTENT_TYPE]);
          $this->setIntuitTid(CoreConstants::INTUIT_TID, $passedHeaders[CoreConstants::INTUIT_TID]);
          $this->setFaultHandler($passedBody, $passedHttpResponseCode, $this->getIntuitTid());
      }else{
          throw new SdkException("Passed Headers, body, or status code is Null.");
      }
   }

Do not parse the response. Just set it as it is.
@param String | Array   http client returned eaders
@param String           http client returned body
@param Int              http client returned status code
@throws  SdkExcpetion   If any of the passed parameter is undefined.

Do not parse the response . Just set it as it is .


private function parseResponseToIntuitResponse($passedHeaders, $passedBody, $passedHttpResponseCode, $clientName){
     if($clientName == CoreConstants::CLIENT_CURL){
        if(isset($passedHeaders)){
            $this->setHeaders($passedHeaders);
        }else{
            throw new SdkException("The response header from cURL is null.");
        }

        if(isset($passedBody)){
            $this->body = $passedBody;
        }else{
            throw new SdkException("The Http Response Body from cURL is null.");
        }

        if(isset($passedHttpResponseCode)){
            $this->httpResponseCode = (int)$passedHttpResponseCode;
            $this->setFaultHandler($this->getBody(), $this->getStatusCode(), $this->getIntuitTid());
        }else{
            throw new SdkException("Passed Http status code from cURL is null.");
        }
     }else{
        throw new SdkException("This should not be thrown. IntuitResponse currently don't support parse other client response to Intuit Response other than curl.");
     }

   }

Parse the response from different http client response and set the Intuit response.
@param String | Array   http client returned eaders
@param String           http client returned body
@param Int              http client returned status code
@param String           http client name

Parse the response from different http client response and set the Intuit response .


private function setFaultHandler($body, $httpResponseCode, $tid){
     //If the status code is non-200
     if($httpResponseCode < 200 || $httpResponseCode >= 300){
        $this->faultHandler = new FaultHandler();
        $this->faultHandler->setHttpStatusCode($httpResponseCode);
        $this->faultHandler->setResponseBody($body);
        $this->faultHandler->setIntuitTid($tid);
        //A standard message for now.
        //TO DO: Wait V3 Team to provide different message for different response.
        $this->faultHandler->setHelpMsg("Invalid auth/bad request (got a " . $httpResponseCode . ", expected HTTP/1.1 20X or a redirect)");
        if($this->getResponseContentType() != null && strcasecmp($this->getResponseContentType(), CoreConstants::CONTENTTYPE_APPLICATIONXML) == 0){
            $this->faultHandler->parseResponse($body);
        }
     }else{
        $this->faultHandler = false;
     }
   }

This is used to set the detailed error coming from QuickBooks Online detail
@param String              Response Body
@param Integer             Response Status code
@param String              Intuit tid on the response header


public function setHeaders($rawHeaders){

        $rawHeaders = str_replace("\r\n", "\n", $rawHeaders);
        $response_headers_rows = explode("\n", trim($rawHeaders));
        foreach ($response_headers_rows as $line) {
            if(strpos($line, ': ') == false){
                continue;
            }else {
                list($key, $value) = explode(': ', $line);
                $this->headers[$key] = $value;
                //set response content type
                $this->setContentType($key, $value);
                $this->setIntuitTid($key, $value);
            }
        }

   }

public
function
setHeaders
(
$
rawHeaders
)
{
$
rawHeaders
=
str_replace
(
"\r\n"
,
"\n"
,
$
rawHeaders
)
;
$
response_headers_rows
=
explode
(
"\n"
,
trim
(
$
rawHeaders
)
)
;
foreach
(
$
response_headers_rows
as
$
line
)
{
if
(
strpos
(
$
line
,
': '
)
==
false
)
{
continue
;
}
else
{
list
(
$
key
,
$
value
)
=
explode
(
': '
,
$
line
)
;
$
this
->
headers
[
$
key
]
=
$
value
;
//set response content type
$
this
->
setContentType
(
$
key
,
$
value
)
;
$
this
->
setIntuitTid
(
$
key
,
$
value
)
;
}
}
}

Parse the raw Http Response Header to associated array to be consumered.
It will also store the Content-Type of the response.
@param string | Array rawHeaders

Parse the raw Http Response Header to associated array to be consumered . It will also store the Content - Type of the response .


private function setContentType($key, $val){
     $trimedKey = trim($key);
     if(strcasecmp($trimedKey, CoreConstants::CONTENT_TYPE) == 0){
         $this->contentType = trim($val);
     }
   }

private function setContentType ( $ key , $ val ) { $ trimedKey = trim ( $ key ) ; if ( strcasecmp ( $ trimedKey , CoreConstants :: CONTENT_TYPE ) == 0 ) { $ this -> contentType = trim ( $ val ) ; } }

Find the headers for response, find the Content-type header and intuit_tid header and set it.
@param String   Header key
@param String   Header value

Find the headers for response find the Content - type header and intuit_tid header and set it .


private function setIntuitTid($key, $val){
     $trimedKey = trim($key);
     if(strcasecmp($trimedKey, CoreConstants::INTUIT_TID) == 0){
         $this->intuit_tid = trim($val);
     }
   }

private function setIntuitTid ( $ key , $ val ) { $ trimedKey = trim ( $ key ) ; if ( strcasecmp ( $ trimedKey , CoreConstants :: INTUIT_TID ) == 0 ) { $ this -> intuit_tid = trim ( $ val ) ; } }

Find the headers for response, find the intuit_tid header and set it.
@param String   Header key
@param String   Header value

Find the headers for response find the intuit_tid header and set it .


public function GetAppMenu()
    {
        $this->requestXmlDocument = '';
        $uriFragment = implode(CoreConstants::SLASH_CHAR, array('v1', 'Account', 'AppMenu'));
        $requestParameters = new RequestParameters(null, 'GET', null, $uriFragment);
        list($respCode, $respHtml) = $this->restRequestHandler->sendRequest($requestParameters, $this->requestXmlDocument, null);
        return $respHtml;
    }

public function GetAppMenu ( ) { $ this -> requestXmlDocument = '' ; $ uriFragment = implode ( CoreConstants :: SLASH_CHAR , array ( 'v1' , 'Account' , 'AppMenu' ) ) ; $ requestParameters = new RequestParameters ( null , 'GET' , null , $ uriFragment ) ; list ( $ respCode , $ respHtml ) = $ this -> restRequestHandler -> sendRequest ( $ requestParameters , $ this -> requestXmlDocument , null ) ; return $ respHtml ; }

Get App Menu

@return string Html of App Menu


public function Reconnect()
    {
        $this->requestXmlDocument = '';
        $uriFragment = implode(CoreConstants::SLASH_CHAR, array('v1', 'Connection', 'Reconnect'));
        $requestParameters = new RequestParameters(null, 'GET', null, $uriFragment);
        list($respCode, $respXml) = $this->restRequestHandler->sendRequest($requestParameters, $this->requestXmlDocument, null);
        return simplexml_load_string($respXml);
    }

public function Reconnect ( ) { $ this -> requestXmlDocument = '' ; $ uriFragment = implode ( CoreConstants :: SLASH_CHAR , array ( 'v1' , 'Connection' , 'Reconnect' ) ) ; $ requestParameters = new RequestParameters ( null , 'GET' , null , $ uriFragment ) ; list ( $ respCode , $ respXml ) = $ this -> restRequestHandler -> sendRequest ( $ requestParameters , $ this -> requestXmlDocument , null ) ; return simplexml_load_string ( $ respXml ) ; }

Reconnect generates a new OAuth access token and invalidates the OAuth access token used
in the request, thereby extending the life span by six months.

@return \SimpleXMLElement Xml of Reconnect response

Reconnect generates a new OAuth access token and invalidates the OAuth access token used in the request thereby extending the life span by six months .


public function setUri($uri)
    {
        if ($uri instanceof Zend_Uri_Http) {
            $uri = $uri->getUri();
        }
        $oldUri = $this->_uri;
        $this->_uri = $uri;

        if ($this->_dom !== null) {
            // @todo: This is the worst hack ever, but its needed due to design and non BC issues of WSDL generation
            $xml = $this->_dom->saveXML();
            $xml = str_replace($oldUri, $uri, $xml);
            $this->_dom = new DOMDocument();
            $this->_dom->loadXML($xml);
        }

        return $this;
    }

Set a new uri for this WSDL

@param  string|Zend_Uri_Http $uri
@return Zend_Server_Wsdl


public function setComplexTypeStrategy($strategy)
    {
        if ($strategy === true) {
            require_once "Zend/Soap/Wsdl/Strategy/DefaultComplexType.php";
            $strategy = new Zend_Soap_Wsdl_Strategy_DefaultComplexType();
        } elseif ($strategy === false) {
            require_once "Zend/Soap/Wsdl/Strategy/AnyType.php";
            $strategy = new Zend_Soap_Wsdl_Strategy_AnyType();
        } elseif (is_string($strategy)) {
            if (class_exists($strategy)) {
                $strategy = new $strategy();
            } else {
                require_once "Zend/Soap/Wsdl/Exception.php";
                throw new Zend_Soap_Wsdl_Exception(
                    sprintf("Strategy with name '%s does not exist.", $strategy
                ));
            }
        }

        if (!($strategy instanceof Zend_Soap_Wsdl_Strategy_Interface)) {
            require_once "Zend/Soap/Wsdl/Exception.php";
            throw new Zend_Soap_Wsdl_Exception("Set a strategy that is not of type 'Zend_Soap_Wsdl_Strategy_Interface'");
        }
        $this->_strategy = $strategy;
        return $this;
    }

Set a strategy for complex type detection and handling

@todo Boolean is for backwards compability with extractComplexType object var. Remove it in later versions.
@param boolean|string|Zend_Soap_Wsdl_Strategy_Interface $strategy
@return Zend_Soap_Wsdl


public function addBindingOperation($binding, $name, $input = false, $output = false, $fault = false)
    {
        $operation = $this->_dom->createElement('operation');
        $operation->setAttribute('name', $name);

        if (is_array($input)) {
            $node = $this->_dom->createElement('input');
            $soap_node = $this->_dom->createElement('soap:body');
            foreach ($input as $name => $value) {
                $soap_node->setAttribute($name, $value);
            }
            $node->appendChild($soap_node);
            $operation->appendChild($node);
        }

        if (is_array($output)) {
            $node = $this->_dom->createElement('output');
            $soap_node = $this->_dom->createElement('soap:body');
            foreach ($output as $name => $value) {
                $soap_node->setAttribute($name, $value);
            }
            $node->appendChild($soap_node);
            $operation->appendChild($node);
        }

        if (is_array($fault)) {
            $node = $this->_dom->createElement('fault');
            if (isset($fault['name'])) {
                $node->setAttribute('name', $fault['name']);
            }
            $soap_node = $this->_dom->createElement('soap:body');
            foreach ($output as $name => $value) {
                $soap_node->setAttribute($name, $value);
            }
            $node->appendChild($soap_node);
            $operation->appendChild($node);
        }

        $binding->appendChild($operation);

        return $operation;
    }

public function addBindingOperation ( $ binding , $ name , $ input = false , $ output = false , $ fault = false ) { $ operation = $ this -> _dom -> createElement ( 'operation' ) ; $ operation -> setAttribute ( 'name' , $ name ) ; if ( is_array ( $ input ) ) { $ node = $ this -> _dom -> createElement ( 'input' ) ; $ soap_node = $ this -> _dom -> createElement ( 'soap:body' ) ; foreach ( $ input as $ name => $ value ) { $ soap_node -> setAttribute ( $ name , $ value ) ; } $ node -> appendChild ( $ soap_node ) ; $ operation -> appendChild ( $ node ) ; } if ( is_array ( $ output ) ) { $ node = $ this -> _dom -> createElement ( 'output' ) ; $ soap_node = $ this -> _dom -> createElement ( 'soap:body' ) ; foreach ( $ output as $ name => $ value ) { $ soap_node -> setAttribute ( $ name , $ value ) ; } $ node -> appendChild ( $ soap_node ) ; $ operation -> appendChild ( $ node ) ; } if ( is_array ( $ fault ) ) { $ node = $ this -> _dom -> createElement ( 'fault' ) ; if ( isset ( $ fault [ 'name' ] ) ) { $ node -> setAttribute ( 'name' , $ fault [ 'name' ] ) ; } $ soap_node = $ this -> _dom -> createElement ( 'soap:body' ) ; foreach ( $ output as $ name => $ value ) { $ soap_node -> setAttribute ( $ name , $ value ) ; } $ node -> appendChild ( $ soap_node ) ; $ operation -> appendChild ( $ node ) ; } $ binding -> appendChild ( $ operation ) ; return $ operation ; }

Add an operation to a binding element

@param object $binding A binding XML_Tree_Node returned by {@link function addBinding}
@param array $input An array of attributes for the input element, allowed keys are: 'use', 'namespace', 'encodingStyle'. {@link http://www.w3.org/TR/wsdl#_soap:body More Information}
@param array $output An array of attributes for the output element, allowed keys are: 'use', 'namespace', 'encodingStyle'. {@link http://www.w3.org/TR/wsdl#_soap:body More Information}
@param array $fault An array of attributes for the fault element, allowed keys are: 'name', 'use', 'namespace', 'encodingStyle'. {@link http://www.w3.org/TR/wsdl#_soap:body More Information}
@return object The new Operation's XML_Tree_Node for use with {@link function addSoapOperation} and {@link function addDocumentation}


public function addDocumentation($input_node, $documentation)
    {
        if ($input_node === $this) {
            $node = $this->_dom->documentElement;
        } else {
            $node = $input_node;
        }

        $doc = $this->_dom->createElement('documentation');
        $doc_cdata = $this->_dom->createTextNode($documentation);
        $doc->appendChild($doc_cdata);

        if ($node->hasChildNodes()) {
            $node->insertBefore($doc, $node->firstChild);
        } else {
            $node->appendChild($doc);
        }

        return $doc;
    }

public function addDocumentation ( $ input_node , $ documentation ) { if ( $ input_node === $ this ) { $ node = $ this -> _dom -> documentElement ; } else { $ node = $ input_node ; } $ doc = $ this -> _dom -> createElement ( 'documentation' ) ; $ doc_cdata = $ this -> _dom -> createTextNode ( $ documentation ) ; $ doc -> appendChild ( $ doc_cdata ) ; if ( $ node -> hasChildNodes ( ) ) { $ node -> insertBefore ( $ doc , $ node -> firstChild ) ; } else { $ node -> appendChild ( $ doc ) ; } return $ doc ; }

Add a documentation element to any element in the WSDL.

Note that the WSDL {@link http://www.w3.org/TR/wsdl#_documentation specification} uses 'document',
but the WSDL {@link http://schemas.xmlsoap.org/wsdl/ schema} uses 'documentation' instead.
The {@link http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html#WSDL_documentation_Element WS-I Basic Profile 1.1} recommends using 'documentation'.

@param object $input_node An XML_Tree_Node returned by another method to add the documentation to
@param string $documentation Human readable documentation for the node
@return DOMElement The documentation element

Add a documentation element to any element in the WSDL .


public function addTypes($types)
    {
        if ($types instanceof DomDocument) {
            $dom = $this->_dom->importNode($types->documentElement);
            $this->_wsdl->appendChild($types->documentElement);
        } elseif ($types instanceof DomNode || $types instanceof DomElement || $types instanceof DomDocumentFragment) {
            $dom = $this->_dom->importNode($types);
            $this->_wsdl->appendChild($dom);
        }
    }

public function addTypes ( $ types ) { if ( $ types instanceof DomDocument ) { $ dom = $ this -> _dom -> importNode ( $ types -> documentElement ) ; $ this -> _wsdl -> appendChild ( $ types -> documentElement ) ; } elseif ( $ types instanceof DomNode || $ types instanceof DomElement || $ types instanceof DomDocumentFragment ) { $ dom = $ this -> _dom -> importNode ( $ types ) ; $ this -> _wsdl -> appendChild ( $ dom ) ; } }

Add WSDL Types element

@param object $types A DomDocument|DomNode|DomElement|DomDocumentFragment with all the XML Schema types defined in it


public function addType($type)
    {
        if (!in_array($type, $this->_includedTypes)) {
            $this->_includedTypes[] = $type;
        }
        return $this;
    }

public function addType ( $ type ) { if ( ! in_array ( $ type , $ this -> _includedTypes ) ) { $ this -> _includedTypes [ ] = $ type ; } return $ this ; }

Add a complex type name that is part of this WSDL and can be used in signatures.

@param string $type
@return Zend_Soap_Wsdl

Add a complex type name that is part of this WSDL and can be used in signatures .


public function dump($filename = false)
    {
        if (!$filename) {
            echo $this->toXML();
            return true;
        } else {
            return file_put_contents($filename, $this->toXML());
        }
    }

public function dump ( $ filename = false ) { if ( ! $ filename ) { echo $ this -> toXML ( ) ; return true ; } else { return file_put_contents ( $ filename , $ this -> toXML ( ) ) ; } }


public function addSchemaTypeSection()
    {
        if ($this->_schema === null) {
            $this->_schema = $this->_dom->createElement('xsd:schema');
            $this->_schema->setAttribute('targetNamespace', $this->_uri);
            $types = $this->_dom->createElement('types');
            $types->appendChild($this->_schema);
            $this->_wsdl->appendChild($types);
        }
        return $this;
    }

public function addSchemaTypeSection ( ) { if ( $ this -> _schema === null ) { $ this -> _schema = $ this -> _dom -> createElement ( 'xsd:schema' ) ; $ this -> _schema -> setAttribute ( 'targetNamespace' , $ this -> _uri ) ; $ types = $ this -> _dom -> createElement ( 'types' ) ; $ types -> appendChild ( $ this -> _schema ) ; $ this -> _wsdl -> appendChild ( $ types ) ; } return $ this ; }

This function makes sure a complex types section and schema additions are set.

@return Zend_Soap_Wsdl

This function makes sure a complex types section and schema additions are set .


public static function ConfigureFromPassedArray(array $settings)
    {
        ServiceContext::checkIfOAuthIsValid($settings);

        if(strcasecmp($settings['auth_mode'], CoreConstants::OAUTH1) == 0) {
             $OAuthConfig = new OAuthRequestValidator(
               $settings['accessTokenKey'],
               $settings['accessTokenSecret'],
               $settings['consumerKey'],
               $settings['consumerSecret']
             );
        }else{
             $OAuthConfig = new OAuth2AccessToken(
               $settings['ClientID'],
               $settings['ClientSecret'],
               CoreConstants::getAccessTokenFromArray($settings),
               CoreConstants::getRefreshTokenFromArray($settings)
             );
        }
        $QBORealmID = array_key_exists('QBORealmID', $settings) ? $settings['QBORealmID'] : null;
        $baseURL =    array_key_exists('baseUrl', $settings) ? $settings['baseUrl']: null;
        if(strcasecmp($baseURL, CoreConstants::DEVELOPMENT_SANDBOX) == 0){
           $baseURL = CoreConstants::SANDBOX_DEVELOPMENT;
        }else if(strcasecmp($baseURL, CoreConstants::PRODUCTION_QBO) == 0){
           $baseURL = CoreConstants::QBO_BASEURL;
        }
        $checkedBaseURL = ServiceContext::checkAndAddBaseURLSlash($baseURL);

        if($OAuthConfig instanceof OAuth2AccessToken){
           $OAuthConfig->setRealmID($QBORealmID);
           $OAuthConfig->setBaseURL($checkedBaseURL);
        }
        $serviceType = CoreConstants::IntuitServicesTypeQBO;
        $IppConfiguration = LocalConfigReader::ReadConfigurationFromParameters($OAuthConfig, $checkedBaseURL, CoreConstants::DEFAULT_LOGGINGLOCATION, CoreConstants::DEFAULT_SDK_MINOR_VERSION);
        $serviceContextInstance = new ServiceContext($QBORealmID, $serviceType, $OAuthConfig, $IppConfiguration);
        return $serviceContextInstance;
    }

public static function ConfigureFromPassedArray ( array $ settings ) { ServiceContext :: checkIfOAuthIsValid ( $ settings ) ; if ( strcasecmp ( $ settings [ 'auth_mode' ] , CoreConstants :: OAUTH1 ) == 0 ) { $ OAuthConfig = new OAuthRequestValidator ( $ settings [ 'accessTokenKey' ] , $ settings [ 'accessTokenSecret' ] , $ settings [ 'consumerKey' ] , $ settings [ 'consumerSecret' ] ) ; } else { $ OAuthConfig = new OAuth2AccessToken ( $ settings [ 'ClientID' ] , $ settings [ 'ClientSecret' ] , CoreConstants :: getAccessTokenFromArray ( $ settings ) , CoreConstants :: getRefreshTokenFromArray ( $ settings ) ) ; } $ QBORealmID = array_key_exists ( 'QBORealmID' , $ settings ) ? $ settings [ 'QBORealmID' ] : null ; $ baseURL = array_key_exists ( 'baseUrl' , $ settings ) ? $ settings [ 'baseUrl' ] : null ; if ( strcasecmp ( $ baseURL , CoreConstants :: DEVELOPMENT_SANDBOX ) == 0 ) { $ baseURL = CoreConstants :: SANDBOX_DEVELOPMENT ; } else if ( strcasecmp ( $ baseURL , CoreConstants :: PRODUCTION_QBO ) == 0 ) { $ baseURL = CoreConstants :: QBO_BASEURL ; } $ checkedBaseURL = ServiceContext :: checkAndAddBaseURLSlash ( $ baseURL ) ; if ( $ OAuthConfig instanceof OAuth2AccessToken ) { $ OAuthConfig -> setRealmID ( $ QBORealmID ) ; $ OAuthConfig -> setBaseURL ( $ checkedBaseURL ) ; } $ serviceType = CoreConstants :: IntuitServicesTypeQBO ; $ IppConfiguration = LocalConfigReader :: ReadConfigurationFromParameters ( $ OAuthConfig , $ checkedBaseURL , CoreConstants :: DEFAULT_LOGGINGLOCATION , CoreConstants :: DEFAULT_SDK_MINOR_VERSION ) ; $ serviceContextInstance = new ServiceContext ( $ QBORealmID , $ serviceType , $ OAuthConfig , $ IppConfiguration ) ; return $ serviceContextInstance ; }

Configure the OAuth 1 or OAuth 2 values from a passed array
@param Array $settings    The array that contains OAuth 1 or OAuth 2 settings


public static function checkIfOAuthIsValid(array $settings){
      if (!isset($settings) || empty($settings)) {
          throw new SdkException("Empty OAuth Array passed. Can't construct ServiceContext based on Empty Array.");
      }

      if(!isset($settings['auth_mode'])){
          throw new SdkException("No OAuth 1 or OAuth 2 Mode specified. Can't validate OAuth tokens.");
      }

      $mode = $settings['auth_mode'];

      //OAuth 1 settings, OAuth 1 must provide all four values.
      if (strcasecmp($mode, CoreConstants::OAUTH1) == 0) {
        if (!isset($settings['accessTokenKey'])) {
            throw new SdkException("'accessTokenKey' must be provided in OAuth1.");
        }

        if (!isset($settings['accessTokenSecret'])) {
            throw new SdkException("'accessTokenSecret' must be provided in OAuth1.");
        }
      }
      //OAuth 2 settings, Only client ID and Client Secret is required. For making API call, all four values, Client ID, Client Secret, Access Token, Access Token Secret are required.
      else if(strcasecmp($mode, CoreConstants::OAUTH2) == 0){
        if (!isset($settings['ClientID'])) {
            throw new SdkException("'ClientID' must be provided in OAuth2.");
        }

        if (!isset($settings['ClientSecret'])) {
            throw new SdkException("'ClientSecret' must be provided in OAuth2.");
        }
      }
      //Now other OAuth is supported
      else{
        throw new SdkException("OAuth Mode is not supported.");
      }
    }

Check if passed array has mininum required fields

@param Array $settings        The array contain OAuth 1 or OAuth 2 settings


public function getBaseURL()
    {
        $this->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called GetBaseURL method.");
        try {
            if ($this->serviceType === CoreConstants::IntuitServicesTypeQBO) {
                $baseurl = $this->IppConfiguration->BaseUrl->Qbo . implode(CoreConstants::SLASH_CHAR, array(CoreConstants::VERSION)) . CoreConstants::SLASH_CHAR;
            }
            else if($this->serviceType === CoreConstants::IntuitServicesTypeIPP){
                $this->IppConfiguration->BaseUrl->Ipp  =  CoreConstants::IPP_BASEURL;
                $baseurl = $this->IppConfiguration->BaseUrl->Ipp;
            }
        } catch (\Exception $e) {
            throw new \Exception("Base URL is not setup");
        }
        return $baseurl;
    }

public
function
getBaseURL
(
)
{
$
this
->
IppConfiguration
->
Logger
->
RequestLog
->
Log
(
TraceLevel
::
Info
,
"Called GetBaseURL method."
)
;
try
{
if
(
$
this
->
serviceType
===
CoreConstants
::
IntuitServicesTypeQBO
)
{
$
baseurl
=
$
this
->
IppConfiguration
->
BaseUrl
->
Qbo
.
implode
(
CoreConstants
::
SLASH_CHAR
,
array
(
CoreConstants
::
VERSION
)
)
.
CoreConstants
::
SLASH_CHAR
;
}
else
if
(
$
this
->
serviceType
===
CoreConstants
::
IntuitServicesTypeIPP
)
{
$
this
->
IppConfiguration
->
BaseUrl
->
Ipp
=
CoreConstants
::
IPP_BASEURL
;
$
baseurl
=
$
this
->
IppConfiguration
->
BaseUrl
->
Ipp
;
}
}
catch
(
\
Exception
$
e
)
{
throw
new
\
Exception
(
"Base URL is not setup"
)
;
}
return
$
baseurl
;
}

Gets the base Uri for a QBO user.

@return string Returns the base Uri endpoint for a user.


public function useXml()
    {
        $this->IppConfiguration->Message->Request->CompressionFormat = CompressionFormat::None;
        $this->IppConfiguration->Message->Response->CompressionFormat = CompressionFormat::None;
        $this->IppConfiguration->Message->Request->SerializationFormat = SerializationFormat::Xml;
        $this->IppConfiguration->Message->Response->SerializationFormat = SerializationFormat::Xml;
    }

public function useXml ( ) { $ this -> IppConfiguration -> Message -> Request -> CompressionFormat = CompressionFormat :: None ; $ this -> IppConfiguration -> Message -> Response -> CompressionFormat = CompressionFormat :: None ; $ this -> IppConfiguration -> Message -> Request -> SerializationFormat = SerializationFormat :: Xml ; $ this -> IppConfiguration -> Message -> Response -> SerializationFormat = SerializationFormat :: Xml ; }

Currently the Object serailziation and deserilization only supports XML format.

Currently the Object serailziation and deserilization only supports XML format .


public function useJson()
    {
        $this->IppConfiguration->Message->Request->CompressionFormat = CompressionFormat::None;
        $this->IppConfiguration->Message->Response->CompressionFormat = CompressionFormat::None;
        $this->IppConfiguration->Message->Request->SerializationFormat = SerializationFormat::Json;
        $this->IppConfiguration->Message->Response->SerializationFormat = SerializationFormat::Json;
    }

public function useJson ( ) { $ this -> IppConfiguration -> Message -> Request -> CompressionFormat = CompressionFormat :: None ; $ this -> IppConfiguration -> Message -> Response -> CompressionFormat = CompressionFormat :: None ; $ this -> IppConfiguration -> Message -> Request -> SerializationFormat = SerializationFormat :: Json ; $ this -> IppConfiguration -> Message -> Response -> SerializationFormat = SerializationFormat :: Json ; }

Currently the Object serailziation and deserilization only supports XML format.
To be Supported, Currently it is only a place holder @Hao

Currently the Object serailziation and deserilization only supports XML format . To be Supported Currently it is only a place holder


public function disableLog()
    {
        try {
            $_ippConfigInstance = $this->getIppConfig();
            LocalConfigReader::setupLogger($_ippConfigInstance, CoreConstants::DEFAULT_LOGGINGLOCATION, "FALSE");
        } catch (\Exception $e) {
            throw new \Exception("Error in disable Log.");
        }
    }

public
function
disableLog
(
)
{
try
{
$
_ippConfigInstance
=
$
this
->
getIppConfig
(
)
;
LocalConfigReader
::
setupLogger
(
$
_ippConfigInstance
,
CoreConstants
::
DEFAULT_LOGGINGLOCATION
,
"FALSE"
)
;
}
catch
(
\
Exception
$
e
)
{
throw
new
\
Exception
(
"Error in disable Log."
)
;
}
}

Disable Log the request and response to disk


public function setLogLocation($new_log_location)
    {
        try {
            $_ippConfigInstance = $this->getIppConfig();
            LocalConfigReader::setupLogger($_ippConfigInstance, $new_log_location, "TRUE");
        } catch (\Exception $e) {
            throw new \Exception("Error in setting up new Log Configuration: " . $new_log_location);
        }
    }

Set a new Location for Log instead of the default Location
@param $new_log_location
The new log directory path. It is a directory, not a file


public function updateOAuth2Token($OAuth2AccessToken){
      if($OAuth2AccessToken instanceof OAuth2AccessToken && $this->requestValidator instanceof OAuth2AccessToken){
        $this->IppConfiguration->Security = $OAuth2AccessToken;
        $this->requestValidator = $OAuth2AccessToken;
      }

    }

public function updateOAuth2Token ( $ OAuth2AccessToken ) { if ( $ OAuth2AccessToken instanceof OAuth2AccessToken && $ this -> requestValidator instanceof OAuth2AccessToken ) { $ this -> IppConfiguration -> Security = $ OAuth2AccessToken ; $ this -> requestValidator = $ OAuth2AccessToken ; } }

Update OAuth 2 Access Token with the new Token Value
@param OAuth2AccessToken  The OAuth 2 token that contains access token, refresh token


public function getClassProperties($props, $indent = "\t")
    {
        $code = $indent."\n";

        foreach ($props as $prop) {
            if (!empty($prop['docs'])) {
                $code .= $indent.$this->getDocBlock($prop['docs'], $indent);
            }
            $code .= $indent.'public $'.$prop['name'].";\n";
        }
        return $code;
    }

public
function
getClassProperties
(
$
props
,
$
indent
=
"\t"
)
{
$
code
=
$
indent
.
"\n"
;
foreach
(
$
props
as
$
prop
)
{
if
(
!
empty
(
$
prop
[
'docs'
]
)
)
{
$
code
.=
$
indent
.
$
this
->
getDocBlock
(
$
prop
[
'docs'
]
,
$
indent
)
;
}
$
code
.=
$
indent
.
'public $'
.
$
prop
[
'name'
]
.
";\n"
;
}
return
$
code
;
}

Return class properties from array with indent specified

@param array $props  Properties array
@param array $indent Indentation in tabs

@return string


public function getResult(){
        if(isset($this->entity)){
            return $this->entity;
        }else if(isset($this->entities)){
            return $this->entities;
        } else{
           return null;
        }
    }

public function getResult ( ) { if ( isset ( $ this -> entity ) ) { return $ this -> entity ; } else if ( isset ( $ this -> entities ) ) { return $ this -> entities ; } else { return null ; } }

Return the result of the Request if there is no error. If the Batch request is Query, the result will be an array of items. If the Batch request is create, update, or ddelete, it will be the entity.
@return Array|IPPIntuitEntity

Return the result of the Request if there is no error . If the Batch request is Query the result will be an array of items . If the Batch request is create update or ddelete it will be the entity .


public function setUri($uri)
    {
        if (!is_string($uri) && !($uri instanceof Zend_Uri)) {
            require_once "Zend/Soap/AutoDiscover/Exception.php";
            throw new Zend_Soap_AutoDiscover_Exception("No uri given to Zend_Soap_AutoDiscover::setUri as string or Zend_Uri instance.");
        }
        $this->_uri = $uri;

        // change uri in WSDL file also if existant
        if ($this->_wsdl instanceof Zend_Soap_Wsdl) {
            $this->_wsdl->setUri($uri);
        }

        return $this;
    }

Set the location at which the WSDL file will be availabe.

@see Zend_Soap_Exception
@throws Zend_Soap_AutoDiscover_Exception
@param  Zend_Uri|string $uri
@return Zend_Soap_AutoDiscover

Set the location at which the WSDL file will be availabe .


public function getUri()
    {
        if ($this->_uri !== null) {
            $uri = $this->_uri;
        } else {
            $schema     = $this->getSchema();
            $host       = $this->getHostName();
            $scriptName = $this->getRequestUriWithoutParameters();
            $uri = Zend_Uri::factory($schema . '://' . $host . $scriptName);
            $this->setUri($uri);
        }
        return $uri;
    }

public function getUri ( ) { if ( $ this -> _uri !== null ) { $ uri = $ this -> _uri ; } else { $ schema = $ this -> getSchema ( ) ; $ host = $ this -> getHostName ( ) ; $ scriptName = $ this -> getRequestUriWithoutParameters ( ) ; $ uri = Zend_Uri :: factory ( $ schema . '://' . $ host . $ scriptName ) ; $ this -> setUri ( $ uri ) ; } return $ uri ; }

Return the current Uri that the SOAP WSDL Service will be located at.

@return Zend_Uri

Return the current Uri that the SOAP WSDL Service will be located at .


protected function getRequestUriWithoutParameters()
    {
        if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch
            $requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
        } elseif (isset($_SERVER['REQUEST_URI'])) {
            $requestUri = $_SERVER['REQUEST_URI'];
        } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI
            $requestUri = $_SERVER['ORIG_PATH_INFO'];
        } else {
            $requestUri = $_SERVER['SCRIPT_NAME'];
        }
        if (($pos = strpos($requestUri, "?")) !== false) {
            $requestUri = substr($requestUri, 0, $pos);
        }

        return $requestUri;
    }

protected
function
getRequestUriWithoutParameters
(
)
{
if
(
isset
(
$
_SERVER
[
'HTTP_X_REWRITE_URL'
]
)
)
{
// check this first so IIS will catch
$
requestUri
=
$
_SERVER
[
'HTTP_X_REWRITE_URL'
]
;
}
elseif
(
isset
(
$
_SERVER
[
'REQUEST_URI'
]
)
)
{
$
requestUri
=
$
_SERVER
[
'REQUEST_URI'
]
;
}
elseif
(
isset
(
$
_SERVER
[
'ORIG_PATH_INFO'
]
)
)
{
// IIS 5.0, PHP as CGI
$
requestUri
=
$
_SERVER
[
'ORIG_PATH_INFO'
]
;
}
else
{
$
requestUri
=
$
_SERVER
[
'SCRIPT_NAME'
]
;
}
if
(
(
$
pos
=
strpos
(
$
requestUri
,
"?"
)
)
!==
false
)
{
$
requestUri
=
substr
(
$
requestUri
,
0
,
$
pos
)
;
}
return
$
requestUri
;
}

Detect and return the current script name without parameters

@return string


public function setComplexTypeStrategy($strategy)
    {
        $this->_strategy = $strategy;
        if ($this->_wsdl instanceof  Zend_Soap_Wsdl) {
            $this->_wsdl->setComplexTypeStrategy($strategy);
        }

        return $this;
    }

public function setComplexTypeStrategy ( $ strategy ) { $ this -> _strategy = $ strategy ; if ( $ this -> _wsdl instanceof Zend_Soap_Wsdl ) { $ this -> _wsdl -> setComplexTypeStrategy ( $ strategy ) ; } return $ this ; }

Set the strategy that handles functions and classes that are added AFTER this call.

@param  boolean|string|Zend_Soap_Wsdl_Strategy_Interface $strategy
@return Zend_Soap_AutoDiscover

Set the strategy that handles functions and classes that are added AFTER this call .


public function setClass($class, $namespace = '', $argv = null)
    {
        $uri = $this->getUri();

        $wsdl = new Zend_Soap_Wsdl($class, $uri, $this->_strategy);

        // The wsdl:types element must precede all other elements (WS-I Basic Profile 1.1 R2023)
        $wsdl->addSchemaTypeSection();

        $port = $wsdl->addPortType($class . 'Port');
        $binding = $wsdl->addBinding($class . 'Binding', 'tns:' .$class. 'Port');

        $wsdl->addSoapBinding($binding, $this->_bindingStyle['style'], $this->_bindingStyle['transport']);
        $wsdl->addService($class . 'Service', $class . 'Port', 'tns:' . $class . 'Binding', $uri);
        foreach ($this->_reflection->reflectClass($class)->getMethods() as $method) {
            $this->_addFunctionToWsdl($method, $wsdl, $port, $binding);
        }
        $this->_wsdl = $wsdl;
        return $this;
    }

Set the Class the SOAP server will use

@param string $class Class Name
@param string $namespace Class Namspace - Not Used
@param array $argv Arguments to instantiate the class - Not Used

@return $this


public function addFunction($function, $namespace = '')
    {
        static $port;
        static $operation;
        static $binding;

        if (!is_array($function)) {
            $function = (array) $function;
        }

        $uri = $this->getUri();

        if (!($this->_wsdl instanceof Zend_Soap_Wsdl)) {
            $parts = explode('.', basename($_SERVER['SCRIPT_NAME']));
            $name = $parts[0];
            $wsdl = new Zend_Soap_Wsdl($name, $uri, $this->_strategy);

            // The wsdl:types element must precede all other elements (WS-I Basic Profile 1.1 R2023)
            $wsdl->addSchemaTypeSection();

            $port = $wsdl->addPortType($name . 'Port');
            $binding = $wsdl->addBinding($name . 'Binding', 'tns:' .$name. 'Port');

            $wsdl->addSoapBinding($binding, $this->_bindingStyle['style'], $this->_bindingStyle['transport']);
            $wsdl->addService($name . 'Service', $name . 'Port', 'tns:' . $name . 'Binding', $uri);
        } else {
            $wsdl = $this->_wsdl;
        }

        foreach ($function as $func) {
            $method = $this->_reflection->reflectFunction($func);
            $this->_addFunctionToWsdl($method, $wsdl, $port, $binding);
        }
        $this->_wsdl = $wsdl;
    }

Add a Single or Multiple Functions to the WSDL

@param string $function Function Name
@param string $namespace Function namespace - Not Used


public function dump($filename)
    {
        if ($this->_wsdl !== null) {
            return $this->_wsdl->dump($filename);
        } else {
            /**
             * @see Zend_Soap_AutoDiscover_Exception
             */
            require_once "Zend/Soap/AutoDiscover/Exception.php";
            throw new Zend_Soap_AutoDiscover_Exception("Cannot dump autodiscovered contents, WSDL file has not been generated yet.");
        }
    }

Proxy to WSDL dump function

@param string $filename


public function updateContext($newServiceContext){
        if(isset($newServiceContext) && $newServiceContext instanceof ServiceContext){
            $this->context = $newServiceContext;
        }else{
           throw new SdkException("Cannot Update Service Context. The service context either is undefined or not an instance of ServiceContext.");
        }
    }

Update the Service Context of the request.

@param ServiceContext  $newServiceContext      The new service context that will be used for the request

Update the Service Context of the request .


public function sendRequest($requestParameters, $requestBody, $specifiedRequestUri, $throwExceptionOnError = false)
    {
        // This step is required since the configuration settings might have been changed.
        $this->resetCompressorAndSerializer();
        //Get the OAuth Authorization Mode for the request, OAuth 1 or OAuth 2.
        $oMode = $this->context->IppConfiguration->OAuthMode;
        // Determine dest URI
        $requestUri = $this->getDestinationURL($requestParameters, $oMode, $specifiedRequestUri);
        //minorVersion support
        $requestUri = $this->appendMinorVersionToRequestURI($requestUri);
        //Check for the HTTP method
        $HttpMethod = $this->checkHTTPMethod($requestParameters);
        $queryParameters = $this->parseURL($requestUri);
        $baseURL = $this->getBaseURL($requestUri);
        if($oMode == CoreConstants::OAUTH1){
          return $this->OAuth1APICall($baseURL, $queryParameters, $HttpMethod, $requestUri, $requestParameters, $requestBody, $throwExceptionOnError);
        } else if ($oMode == CoreConstants::OAUTH2){
          return $this->OAuth2APICall($baseURL, $queryParameters, $HttpMethod, $requestUri, $requestParameters, $requestBody, $throwExceptionOnError);
        } else{
           throw new SdkException("OAuth Mode not supported.");
        }
    }

Sending an request to QuickBooks Online based on the Request parameters, body and URI.

@param  RequestParameters $requestParameters     The request parameter for this API Call
@param  String           $requestBody           The body of the API call
@param  String           $specifiedRequestUri   The user specified URI for the request
@param  Boolean          $throwExceptionOnError If throw an exception whent he return http status is not 200. Default is false
@return null|array       APIResult              The result of this Http Request.

Sending an request to QuickBooks Online based on the Request parameters body and URI .


private function OAuth1APICall($baseURL, $queryParameters, $HttpMethod, $requestUri, $requestParameters, $requestBody, $throwExceptionOnError){
      $AuthorizationHeader = $this->getOAuth1AuthorizationHeader($baseURL, $queryParameters, $HttpMethod);
      $httpHeaders = $this->setCommonHeadersForPHPSDK($AuthorizationHeader, $requestUri, $requestParameters->ContentType, $requestBody);
      // Log Request Body to a file
      $this->LogAPIRequestToLog($requestBody, $requestUri, $httpHeaders);
      $intuitResponse = $this->httpClientInterface->makeAPICall($requestUri, $HttpMethod, $httpHeaders, $requestBody, null, false);
      $faultHandler = $intuitResponse->getFaultHandler();
      $this->LogAPIResponseToLog($intuitResponse->getBody(), $requestUri, $intuitResponse->getHeaders());
      //Based on the ducomentation, the fetch expected HTTP/1.1 20X or a redirect. If not, any 3xx, 4xx or 5xx will throw an OAuth Exception
      //for 3xx without direct, it will throw a 503 code and error saying: Invalid protected resource url, unable to generate signature base string
      if($faultHandler) {
          if($throwExceptionOnError == true){
              throw new ServiceException("Request is not made successful. Body: [" . $faultHandler->getResponseBody() . "].", $faultHandler->getHttpStatusCode());
          }else{
              $this->faultHandler = $faultHandler;
              return null;
          }
      }else{
         $this->faultHandler = false;
      }
      return array($intuitResponse->getStatusCode(),$intuitResponse->getBody());
    }

The API call to generate OAuth 1 signatures and make API call

@param  String           $baseURL               The request url without queryParameters
@param  Array            $queryParameters       A list of query parameters
@param  String           $HttpMethod            POST or GET
@param  String           $requestUri            The Complete HTTP request URI
@param  Array            $requestParameters     The Complete HTTP request URI
@param  String           $requestBody           The request body for POST request.
@param  Boolean          $throwExceptionOnError If throw an exception whent he return http status is not 200. Default is false

@return Response and HTTP Status code


private function getOAuth1AuthorizationHeader($baseURL, $queryParameters, $HttpMethod){
      $oauth1 = new OAuth1(
        $this->context->requestValidator->ConsumerKey,
        $this->context->requestValidator->ConsumerSecret,
        $this->context->requestValidator->AccessToken,
        $this->context->requestValidator->AccessTokenSecret
      );

      $AuthorizationHeader = $oauth1->getOAuthHeader($baseURL, $queryParameters, $HttpMethod);
      return $AuthorizationHeader;
    }

private function getOAuth1AuthorizationHeader ( $ baseURL , $ queryParameters , $ HttpMethod ) { $ oauth1 = new OAuth1 ( $ this -> context -> requestValidator -> ConsumerKey , $ this -> context -> requestValidator -> ConsumerSecret , $ this -> context -> requestValidator -> AccessToken , $ this -> context -> requestValidator -> AccessTokenSecret ) ; $ AuthorizationHeader = $ oauth1 -> getOAuthHeader ( $ baseURL , $ queryParameters , $ HttpMethod ) ; return $ AuthorizationHeader ; }

Get OAuth1 Authroization Header based on Query Parameters, BaseURL
@param String   $baseURL            The baseURL without queryParameters
@param Array    $queryParameters    The queryParameters list from the complete URI
@param String   $httpMethod         POST or GET
@return OAuth1 Authorization Header

Get OAuth1 Authroization Header based on Query Parameters BaseURL


private function OAuth2APICall($baseURL, $queryParameters, $HttpMethod, $requestUri, $requestParameters, $requestBody, $throwExceptionOnError){
        $AuthorizationHeader = $this->getOAuth2AuthorizationHeader($this->context->requestValidator);
        //We only support QBO for PHP SDK. No QBD support, change
        // from: if ('QBO'==$this->context->serviceType || 'QBD'==$this->context->serviceType)
        if (CoreConstants::IntuitServicesTypeQBO ==$this->context->serviceType) {
            // IDS call
            $httpHeaders = $this->setCommonHeadersForPHPSDK($AuthorizationHeader, $requestUri, $requestParameters->ContentType, $requestBody);
            // Log Request Body to a file
            $this->LogAPIRequestToLog($requestBody, $requestUri, $httpHeaders);
        } else {
             throw new SdkException("IPP or other Call is not supported in OAuth2 Mode.");
        }

        $intuitResponse = $this->httpClientInterface->makeAPICall($requestUri, $HttpMethod, $httpHeaders,  $requestBody, null, true);
        $faultHandler = $intuitResponse->getFaultHandler();
        $this->LogAPIResponseToLog($intuitResponse->getBody(), $requestUri, $intuitResponse->getHeaders());
        //Based on the ducomentation, the fetch expected HTTP/1.1 20X or a redirect. If not, any 3xx, 4xx or 5xx will throw an OAuth Exception
        //for 3xx without direct, it will throw a 503 code and error saying: Invalid protected resource url, unable to generate signature base string
        if($faultHandler) {
            if($throwExceptionOnError == true){
                throw new ServiceException("Request is not made successful. Response Code:[" . $faultHandler->getHttpStatusCode() . "] with body: [" . $faultHandler->getResponseBody() . "].", $faultHandler->getHttpStatusCode());
            }else{
                $this->faultHandler = $faultHandler;
                return null;
            }
        }else{
            $this->faultHandler = false;
        }
        return array($intuitResponse->getStatusCode(),$intuitResponse->getBody());
    }

The OAuth 2 API call

@param  String           $baseURL               The request url without queryParameters
@param  Array            $queryParameters       A list of query parameters
@param  String           $HttpMethod            POST or GET
@param  String           $requestUri            The Complete HTTP request URI
@param  Array            $requestParameters     The Complete HTTP request URI
@param  String           $requestBody           The request body for POST request.
@param  Boolean          $throwExceptionOnError If throw an exception whent he return http status is not 200. Default is false

@return array|null Response and HTTP Status code


private function getOAuth2AuthorizationHeader($OAuth2AccessToken){
      if(!$OAuth2AccessToken instanceof OAuth2AccessToken){
         throw new SdkException("Internal Error. The OAuth 2 configuration is not complete.");
      }

      $accessToken = $OAuth2AccessToken->getAccessToken();
      $AuthorizationHeader = "Bearer " . $accessToken;
      return $AuthorizationHeader;
    }

Get OAuth2 Authroization Header based on OAuth 2 Access Token

@param OAuth2AccessToken   $OAuth2AccessToken     The OAuth 2 token contains AccessToken, RefreshToken, ClientID and Client Secret.
@return string OAuth2 Authorization Header


public function LogAPIResponseToLog($body, $requestUri, $httpHeaders){
      if(strcasecmp($httpHeaders[CoreConstants::CONTENT_TYPE], CoreConstants::CONTENTTYPE_APPLICATIONXML) == 0 ||
          strcasecmp($httpHeaders[CoreConstants::CONTENT_TYPE], CoreConstants::CONTENTTYPE_APPLICATIONXML_WITH_CHARSET) == 0){
             $body = $this->parseStringToDom($body);
      }

      $this->RequestLogging->LogPlatformRequests($body, $requestUri, $httpHeaders, false);
    }

public function LogAPIResponseToLog ( $ body , $ requestUri , $ httpHeaders ) { if ( strcasecmp ( $ httpHeaders [ CoreConstants :: CONTENT_TYPE ] , CoreConstants :: CONTENTTYPE_APPLICATIONXML ) == 0 || strcasecmp ( $ httpHeaders [ CoreConstants :: CONTENT_TYPE ] , CoreConstants :: CONTENTTYPE_APPLICATIONXML_WITH_CHARSET ) == 0 ) { $ body = $ this -> parseStringToDom ( $ body ) ; } $ this -> RequestLogging -> LogPlatformRequests ( $ body , $ requestUri , $ httpHeaders , false ) ; }

Log API Reponse to the Log directory that user specified.
@param String $body The requestBody
@param String $requestUri  The URI for this request
@param Array $httpHeaders  The headers for the request

Log API Reponse to the Log directory that user specified .