private function requestXml($scope, $name, array $opts = array())
{
$opts = array_merge(Config::getInstance()->additional_request_parameters, $opts);
// apikey/userid/keyid|vcode shouldn't be allowed in arguments and removed to avoid wrong cached api calls
foreach ($opts as $k => $v) {
if (in_array(strtolower($k), array('userid', 'apikey', 'keyid', 'vcode'))) {
unset($opts[$k]);
}
}
// prepare http arguments + url (to not modify original argument list for cache saving)
$url = Config::getInstance()->api_base . $scope . '/' . $name . '.xml.aspx';
$use_customkey = (bool) Config::getInstance()->api_customkeys;
$http_opts = $opts;
if ($this->userid) {
$http_opts[$use_customkey ? 'keyID' : 'userid'] = $this->userid;
}
if ($this->key) {
$http_opts[$use_customkey ? 'vCode' : 'apikey'] = $this->key;
}
// check access level if given (throws PhealAccessExpception if API call is not allowed)
if ($use_customkey && $this->userid && $this->key && $this->keyType) {
try {
Config::getInstance()->access->check($scope, $name, $this->keyType, $this->accessMask);
} catch (\Exception $e) {
Config::getInstance()->log->errorLog($scope, $name, $http_opts, $e->getMessage());
throw $e;
}
}
// check cache first
if (!($this->xml = Config::getInstance()->cache->load($this->userid, $this->key, $scope, $name, $opts))) {
try {
// start measure the response time
Config::getInstance()->log->start();
// rate limit
Config::getInstance()->rateLimiter->rateLimit();
$config = Config::getInstance();
// request
$this->xml = $config->fetcher->fetch($url, $http_opts);
// stop measure the response time
Config::getInstance()->log->stop();
$element = @new \SimpleXMLElement($this->xml);
// check if we could parse this
if ($element === false) {
$errmsgs = '';
foreach (libxml_get_errors() as $error) {
$errmsgs .= $error->message . "\n";
}
throw new PhealException('XML Parser Error: ' . $errmsgs);
}
// archive+save only non-error api calls + logging
if (!$element->error) {
Config::getInstance()->log->log($scope, $name, $http_opts);
Config::getInstance()->archive->save($this->userid, $this->key, $scope, $name, $opts, $this->xml);
} else {
Config::getInstance()->log->errorLog($scope, $name, $http_opts, $element->error['code'] . ': ' . $element->error);
}
Config::getInstance()->cache->save($this->userid, $this->key, $scope, $name, $opts, $this->xml);
// just forward HTTP Errors
} catch (HTTPException $e) {
throw $e;
// ensure that connection exceptions are passed on
} catch (ConnectionException $e) {
throw $e;
// other request errors
} catch (\Exception $e) {
// log + throw error
Config::getInstance()->log->errorLog($scope, $name, $http_opts, $e->getCode() . ': ' . $e->getMessage());
throw new PhealException('Original exception: ' . $e->getMessage(), $e->getCode(), $e);
}
} else {
$element = @new \SimpleXMLElement($this->xml);
}
return new Result($element);
}