Задать вопрос
@PGSky

Как улучшить обработку ответа от API по протоколу SOAP?

Есть задача, подключить Booking-Manager.com API к сайту. API использует протокол SOAP

Я вроде все подключил и форму поиска написал, но грузятся результаты очень долго

Ответ от сервера, при использовании поиска, получаю в таком виде:
<root>
<resource resourceid="" companyid=”” reservationstatus="" baseprice="" 
discountvalue="" price="" baseid=”” datefrom=”” dateto=””></resource>
…
</root>

Т.е., по факту, список Ресурсов. Но данных для вывода мало и потому мне приходится по каждому элементу списка проходиться отдельно (через While) и получать информацию по каждому ресурсу из списка

Приведу несколько кусков кода
Собственно, обработка полученного XML от сервера после поиска для сбора массива и дальнейшего вызова функции получения информации по каждому ID:

function getSearchResults($dataConnect,$_xmlValues,$fieldsMain) {
	$connectOptions = $dataConnect;
	$struct = array($connectOptions['id'], $connectOptions['email'], $connectOptions['password'], $_xmlValues);
	$result = soapClientResult($struct,'getSearchResultsFilter');
	
	$resources_final = array();
	
	if (!is_soap_fault($result)) {
		try {
			if(isset($result->out)) {
				
				$resources = array();
				$xml = $result->out;
				
				$reader = new XMLReader();
				$reader->xml($xml);
				
				$dom = new DOMDocument();
				
				$i = 0;
				while($reader->read()) {
					if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == "resource") {
						$node = simplexml_import_dom($dom->importNode($reader->expand(), true));
						$resources[$i]['resourceid'] = $reader->getAttribute('resourceid');
						$resources[$i]['baseprice'] = $reader->getAttribute('baseprice');
						$resources[$i]['reservationstatus'] = $reader->getAttribute('reservationstatus');
						$resources[$i]['baseid'] = $reader->getAttribute('baseid');
						$i++;
					}
				}
				$reader->close();
				
				$i = 0;
				foreach ($resources as $resource) {
					$resources_final[$i] = get_xml_soap_single($connectOptions,$resource['resourceid'],false,$fieldsMain);
					if($i == 50) {
						break;
					}
					$i++;
				}
			}
		}
		catch (Exception $e) {
			print_r($e->getMessage());
			echo '<br>';
			print_r($soapClient->__getLastRequest());
			echo '<br>';
			print_r($soapClient->__getLastResponse());
		}
	} else {
		return 'error';
	}
	return $resources;
}


А здесь, собственно и сама обработка ресурса

//SOAP CLIENT
function get_soapClient() {
	$wsdl = 'https://www.booking-manager.com/cbm_web_service2/services/CBM?wsdl';
	$arrContextOptions=array("ssl"=>array( "verify_peer"=>false, "verify_peer_name"=>false,'crypto_method' => STREAM_CRYPTO_METHOD_TLS_CLIENT)); 
	$options = array(
			'exceptions'=>false,
			'trace'=>1,
			'stream_context' => stream_context_create($arrContextOptions),
			'keep_alive' => true,
	);
	$soapClient = new SoapClient($wsdl, $options);
	return $soapClient;
}

//Cбор аттрибутов отдельных элементов XML по Name 
function soapXMLReaderGetResult($dom,$reader,$resource,$result_final,$result_source,$array_name,$final,$count,$current_count) {
	if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == $resource) {
		$node = simplexml_import_dom($dom->importNode($reader->expand(), true));
		if($reader->hasAttributes)  {
			while($reader->moveToNextAttribute()) { 
				if($count == true) {
					if($final == true) {
						$result_final[$array_name][$current_count][$reader->name] = $reader->value;
					} else {
						$result_source[$array_name][$current_count][$reader->name] = $reader->value;
					}
				} else {
					if($final == true) {
						$result_final[$array_name][$reader->name] = $reader->value;
					} else {
						$result_source[$array_name][$reader->name] = $reader->value;
					}
				}
			}
		}
	}
	if($final == true) {
		return $result_final[$array_name];
	} else {
		return $result_source[$array_name];
	}
}

// Инициализация подключения к SOAP

function soapClientResult($struct_result, $struct_function) {

	$soapClient = get_soapClient();
	
	$struct = new MMKStruct($struct_result);
	$result = $soapClient->__soapCall($struct_function,array($struct));
	
	return $result;
}

// Собственно сама обработка ресурса

function get_xml_soap_single($dataConnect,$request_id,$single = bool,$fieldsSearch) {
	
		$pathImages = $_SERVER['DOCUMENT_ROOT'] . '/tmp/images';
		
		if(!file_exists($pathImages)) {
			mkdir($pathImages,0755,true);
		} else {
			foreach (glob($pathImages.'/*') as $file) {
				unlink($file);
			}
		}
	
		$currentDate = date('Y-m-d');
		
		$connectOptions = $dataConnect;
		
		$struct = array($connectOptions['id'], $connectOptions['email'], $connectOptions['password'], $request_id);
		$result = soapClientResult($struct,'getResourceDetails');
		
		if (!is_soap_fault($result)) {
			
			try {
				
				$result_source = array();
				$result_source['prices_source'] = array();
				$result_source['images_source'] = array();
				$result_source['locations_source'] = array();
				
				$result_final = array();
				$result_final['attributes'] = array();
				$result_final['prices_current'] = array();
				$result_final['images_final'] = array();
				$result_final['locations_current'] = array();
				$result_final['locations_current_base'] = array();
				
				if(isset($result->out)) {
			
					$xml = $result->out;
					$reader = new XMLReader();
					$reader->xml($xml);
					
					$dom = new DOMDocument();
					
					$resource_count = 0;
					$prices_count = $images_count = $equipment_count = $extras_count = $discounts_count = $products_count = $locations_count = 0;
					
					while($reader->read()) {
						
						if ($reader->nodeType == XMLReader::ELEMENT) {
							if($reader->name == 'resource') {
								$resource_count = 0;
							}
							if ($reader->name == 'price') {
								++$prices_count;
							}
							if ($reader->name == 'image') {
								++$images_count;
							}
							if ($reader->name == 'location') {
								++$locations_count;
							}
						}
						
						$result_final['attributes'] = soapXMLReaderGetResult($dom,$reader,'resource',$result_final,$result_source,'attributes',true,false,$resource_count);
						
						$result_source['prices_source'] = soapXMLReaderGetResult($dom,$reader,'price',$result_final,$result_source,'prices_source',false,true,$prices_count);
						
						$result_source['images_source'] = soapXMLReaderGetResult($dom,$reader,'image',$result_final,$result_source,'images_source',false,true,$images_count);
						
						$result_source['locations_source'] = soapXMLReaderGetResult($dom,$reader,'location',$result_final,$result_source,'locations_source',false,true,$locations_count);
						
						
					}
					$reader->close();
					
					usort($result_source['images_source'], "images_sort_main");
					if(file_exists($_SERVER['DOCUMENT_ROOT'] . '/tmp/images')) {
						$i = 0;
						foreach ($result_source['images_source'] as $image) {
							$fileBasename = basename($image['href']);
							$result_final['images_final'][$i]['href'] = '/tmp/images/' . $fileBasename;
							$result_final['images_final'][$i]['comment'] = $image['comment'];
							$i++;
						}
					}
					
					usort($result_source['prices_source'], "cmp_date");
					
					$alignment_validate = false;
					foreach ($result_source['prices_source'] as $price) {
						if(strtotime($price['datefrom']) < strtotime($currentDate) && strtotime($price['dateto']) > strtotime($currentDate)) {
							foreach($price as $key => $val) {
								$result_final['prices_current'][$key] = $val;
							}
							$alignment_validate = true;
							break;
						}
					}
					if(!$alignment_validate) {
						foreach ($result_source['prices_source'][0] as $key => $val) {
							$result_final['prices_current'][$key] = $val;
						}
					}
					
					if($result_source['locations_source'] != 0) {
						usort($result_source['locations_source'], "cmp_date");
						
						$alignment_validate = false;
						foreach ($result_source['locations_source'] as $price) {
							if(strtotime($price['datefrom']) < strtotime($currentDate) && strtotime($price['dateto']) > strtotime($currentDate)) {
								foreach($price as $key => $val) {
									$result_final['locations_current'][$key] = $val;
								}
								$alignment_validate = true;
								break;
							}
						}
						if(!$alignment_validate) {
							foreach ($result_source['locations_source'][0] as $key => $val) {
								$result_final['locations_current'][$key] = $val;
							}
						}
						
						if($result_final['locations_current'] != 0) {
							$baseCurrent = soapClientBasesCurrent($result_final['locations_current']['baseid'],$fieldsSearch);
							if($baseCurrent != false) {
								$result_final['locations_current_base'] = $baseCurrent;
							}
						}
					}
					
					if($result_final != 0) {
						return $result_final;
					}
					
				}
			}
			
			catch (Exception $e) {
				print_r($e->getMessage());
				echo '<br>';
				print_r($soapClient->__getLastRequest());
				echo '<br>';
				print_r($soapClient->__getLastResponse());
			}
			
		} else {
			return false;
		}
}


Так вот. Моим способом, получается, что каждый полученный ресурс от сервера, обрабатывается отдельно через XML Reader. Т.е. в начале цикл для сбора данных ответа в массив. Потом получившийся массив используется для вызова функции обработки Ресурса и отправки туда ID для дальнейшей обработки Ресурса. В самом ресурсе цикл по сбору данных ресурса в том виде в котором мне надо.
В итоге, грубо говоря на 50 ресурсов, получается 50 циклов по сбору данных по ресурсу. К тому же 50 запросов к серверу SOAP, дабы получить необходимый XML

Вопрос: это нормально и можно ли как-то исправить если нет? Если да, то подскажите как улучшить код, пожалуйста. В текущем виде, данные получает долго (и многое влияет то, сколько ID получил от сервера). Уже несколько дней с этим вожусь и в голову ничего стоящего не приходит
  • Вопрос задан
  • 172 просмотра
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ответы на вопрос 1
@lubezniy
Если в API нет другой возможности по расширенному получению данных, нужно либо сокращать объём выводимого до списка (если задача позволяет), либо вообще выводить получение данных в отдельный процесс (daemon), не связанный с выдачей ответов пользователю, с организацией очереди обработки и выдачи результатов через время, превышающее настройки таймаутов web-сервера.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы