Completed
Pull Request — master (#17)
by
unknown
01:17
created

Ares::loadByIdentificationNumbers()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 49
rs 8.8016
c 0
b 0
f 0
cc 5
nc 8
nop 2
1
<?php declare(strict_types=1);
2
3
namespace h4kuna\Ares;
4
5
use h4kuna\Ares\Exceptions\ConnectionException;
6
use h4kuna\Ares\Exceptions\IdentificationNumberNotFoundException;
7
8
class Ares
9
{
10
11
	public const URL = 'https://wwwinfo.mfcr.cz/cgi-bin/ares/darv_bas.cgi';
12
	public const POST_URL = 'https://wwwinfo.mfcr.cz/cgi-bin/ares/xar.cgi';
13
	private const POST_IDENTIFICATION_NUMBERS_LIMIT = 100; // in one post request can be max 100 identification numbers
14
15
	/** @var IFactory */
16
	private $factory;
17
18
	/** @var DataProvider */
19
	private $dataProvider;
20
21
22
	public function __construct(IFactory $factory = null)
23
	{
24
		if ($factory === null) {
25
			$factory = new Factory();
26
		}
27
		$this->factory = $factory;
28
	}
29
30
31
	/**
32
	 * @param array|string[] $identificationNumbers
33
	 * @param array $options
34
	 * @return array|Data[]|Error[]
35
	 * @throws \GuzzleHttp\Exception\GuzzleException
36
	 * @throws \Exception
37
	 */
38
	public function loadByIdentificationNumbers(array $identificationNumbers, $options = []): array
39
	{
40
		$client = $this->factory->createGuzzleClient($options);
41
		$offset = 0;
42
		$output = [];
43
44
		$identificationNumbersCount = count($identificationNumbers);
45
		while (($identificationNumbersCount - $offset) > 0) {
46
			$identificationNumbersBatch = array_slice($identificationNumbers, $offset,self::POST_IDENTIFICATION_NUMBERS_LIMIT, TRUE);
47
			$offset += self::POST_IDENTIFICATION_NUMBERS_LIMIT;
48
49
			$response = $client->request('POST', self::POST_URL, [
50
				'headers' => [
51
					'Content-type' => 'application/xml'
52
				],
53
				'body' => $this->factory->createBodyFactory()->createBodyContent($identificationNumbersBatch)
54
			]);
55
56
57
			$simpleXml = simplexml_load_string($response->getBody()->getContents(), null, 0, 'SOAP-ENV', true);
58
			$simpleXml->registerXPathNamespace('SOAP-ENV', 'http://schemas.xmlsoap.org/soap/envelope/');
59
60
61
			$responseData = $simpleXml->children('SOAP-ENV', true)
62
				->Body
63
				->children('are', true)
64
				->children('are', true);
65
66
			foreach ($responseData as $item) {
67
				$D = $item->children('D' , true);
68
				$pid = (int) $D->PID->__toString();
69
70
				try {
71
					if($D->E->asXML() !== FALSE) {
72
						$DE = $D->E->children('D', TRUE);
73
						throw new IdentificationNumberNotFoundException(trim($DE->ET->__toString()), $DE->EK->__toString());
74
					}
75
76
					$this->processXml($D->VBAS, $this->getDataProvider()->prepareData());
77
78
					$output[$pid] = $this->getData();
79
				} catch (IdentificationNumberNotFoundException $exception) {
80
					$output[$pid] = new Error($exception->getCode(), $exception->getMessage());
81
				}
82
			}
83
		}
84
85
		return $output;
86
	}
87
88
89
	/**
90
	 * Load fresh data.
91
	 * @throws IdentificationNumberNotFoundException
92
	 */
93
	public function loadData(string $in, array $options = []): Data
94
	{
95
		$this->loadXML($in, $options);
96
		return $this->getData();
97
	}
98
99
100
	/**
101
	 * Get temporary data.
102
	 */
103
	public function getData(): Data
104
	{
105
		return $this->getDataProvider()->getData();
106
	}
107
108
109
	/**
110
	 * Load XML and fill Data object
111
	 * @throws IdentificationNumberNotFoundException
112
	 */
113
	private function loadXML(string $in, array $options)
114
	{
115
		$client = $this->factory->createGuzzleClient($options);
116
		try {
117
			$xmlSource = $client->request('GET', $this->createUrl($in))->getBody()->getContents();
118
		} catch (\Throwable $e) {
119
			throw new ConnectionException($e->getMessage(), $e->getCode(), $e);
120
		}
121
		$xml = @simplexml_load_string($xmlSource);
122
		if (!$xml) {
123
			throw new ConnectionException();
124
		}
125
126
		$ns = $xml->getDocNamespaces();
127
		$answer = $xml->children($ns['are'])->children($ns['D']);
128
		$this->parseErrorAnswer($xml, $in);
129
		$this->processXml($answer->VBAS, $this->getDataProvider()->prepareData());
130
	}
131
132
133
	protected function processXml(\SimpleXMLElement $xml, DataProvider $dataProvider): void
134
	{
135
		$dataProvider->setIN((string) $xml->ICO)
136
			->setTIN((string) $xml->DIC)
137
			->setCompany((string) $xml->OF)
138
			->setZip(self::exists($xml->AA, 'PSC'))
139
			->setStreet(self::exists($xml->AA, 'NU'))
140
			->setCity(self::exists($xml->AA, 'N'))
141
			->setHouseNumber(self::exists($xml->AA, 'CD'), self::exists($xml->AA, 'CO'), self::exists($xml->AA, 'CA'))
142
			->setCityPost(self::exists($xml->AA, 'NMC'))
143
			->setCityDistrict(self::exists($xml->AA, 'NCO'))
144
			->setIsPerson(self::exists($xml->PF, 'KPF'))
145
			->setCreated((string) $xml->DV)
146
			->setNace(self::existsArray($xml->Nace, 'NACE'));
147
148
		$dataProvider->setDissolved(isset($xml->DZ) ? (string) $xml->DZ : null);
149
150
		if (isset($xml->ROR)) {
151
			$dataProvider
152
				->setFileNumber((string) $xml->ROR->SZ->OV)
153
				->setCourt((string) $xml->ROR->SZ->SD->T);
154
		} else {
155
			$dataProvider
156
				->setFileNumber('')
157
				->setCourt('');
158
		}
159
	}
160
161
162
	private function createUrl(string $inn): string
163
	{
164
		$parameters = [
165
			'ico' => $inn,
166
			'aktivni' => 'false',
167
		];
168
		return self::URL . '?' . http_build_query($parameters);
169
	}
170
171
172
	private function getDataProvider(): DataProvider
173
	{
174
		if ($this->dataProvider === null) {
175
			$this->dataProvider = $this->factory->createDataProvider();
176
		}
177
		return $this->dataProvider;
178
	}
179
180
181
	private static function exists(\SimpleXMLElement $element, string $property): string
182
	{
183
		return isset($element->{$property}) ? ((string) $element->{$property}) : '';
184
	}
185
186
187
	private static function existsArray(\SimpleXMLElement $element, string $property): array
188
	{
189
		return isset($element->{$property}) ? ((array) $element->{$property}) : [];
190
	}
191
192
193
	private function parseErrorAnswer(\SimpleXMLElement $answer, string $in): void
194
	{
195
		$errorMessage = self::xmlValue($answer, '//D:ET[1]');
196
		$errorCode = self::xmlValue($answer, '//D:EK[1]');
197
		if ($errorMessage === null && $errorCode === null) {
198
			return;
199
		}
200
201
		// 61 - subject disappeared
202
		// 71 - not exists
203
		if (empty($errorMessage)) {
204
			throw new ConnectionException();
205
		}
206
		throw new IdentificationNumberNotFoundException(sprintf('IN "%s". %s', $in, $errorMessage), (int) $errorCode);
207
	}
208
209
210
	private static function xmlValue(\SimpleXMLElement $xml, string $xpath): ?string
211
	{
212
		$result = $xml->xpath($xpath);
213
		if ($result === []) {
214
			return null;
215
		}
216
		return trim((string) $result[0]);
217
	}
218
219
}
220