Test Failed
Push — master ( fb7e43...d555d2 )
by Carsten
05:59 queued 12s
created

GuzzleGeoDataFactory::__construct()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 10
cc 2
nc 1
nop 2
crap 2
1
<?php
2
namespace Germania\GeoData;
3
4
use GuzzleHttp\Client as GuzzleClient;
5
use GuzzleHttp\Exception\RequestException;
6
use Germania\GeoData\GeoData;
7
use Germania\GeoData\GeoDataFactory;
8
use Psr\Log\LoggerInterface;
9
use Psr\Log\LoggerAwareInterface;
10
use Psr\Log\LoggerAwareTrait;
11
use Psr\Log\NullLogger;
12
13
14
class GuzzleGeoDataFactory implements LoggerAwareInterface
15
{
16
17
	use LoggerAwareTrait;
18
19
	/**
20
	 * @var \GuzzleHttp\Client
21
	 */
22
	public $http_client;
23
24
25
	/**
26
	 * @var string
27
	 */
28
	public $url_path = "coordinates";
29
30
31
	/**
32
	 * @var GeoDataFactory
33
	 */
34
	public $geodata_factory;
35
36
37
	/**
38
	 * @param GuzzleClient    $http_client Guzzle Client, configured for Germania's GeoCoder API
39
	 * @param LoggerInterface $logger          PSR-3 Logger
40
	 */
41 4
	public function __construct(GuzzleClient $http_client, LoggerInterface $logger = null)
42
	{
43 4
		$this->http_client = $http_client;
44 4
		$this->geodata_factory = new GeoDataFactory;
45 4
		$this->setLogger($logger ?: new NullLogger);
46 4
	}
47
48
49
	/**
50
	 * @param  string $location [description]
51
	 * @return GeoData
52
	 * @throws \RuntimeException
53
	 */
54 2
	public function fromString( string $location ) : GeoData
55
	{
56
		try {
57
			// Guzzle client returns ResponseInterface!
58 2
			$response = $this->http_client->get( $this->url_path, [
59 2
				"query" => ['search' => $location]
60
			]);
61
		}
62
		catch (RequestException $e) {
63
			$msg = sprintf("Error on Geocoder API request: %s", $e->getMessage());
64
			$this->logger->log( "error", $msg, [
65
				'exception' => get_class($e)
66
			]);
67
			throw new GeoDataFactoryRuntimeException($msg, 0, $e);
68
		}		
69
70
71
72
		try {
73 2
			$response_body = $response->getBody();
74 2
			$response_body_decoded = json_decode($response_body, "associative");
75 2
			$this->validateDecodedResponse( $response_body_decoded );	
76
		}
77
		catch (\Throwable $e) {
78
			$msg = sprintf("Error on Geocoder API response validation: %s", $e->getMessage());			
79
			$this->logger->log( "error", $msg, [
80
				'exception' => get_class($e)
81
			]);
82
			throw new GeoDataFactoryRuntimeException($msg, 0, $e);
83
		}
84
85
			
86 2
		$coordinates_raw = $response_body_decoded['data']["attributes"];
87 2
		$geodata = $this->geodata_factory->fromArray( $coordinates_raw );
88
89
90 2
		return $geodata;
91
	}
92
93
94
95
96
	/**
97
	 * Validates the decoded response, throwing things in error case.
98
	 * 
99
	 * @param  mixed $response_body_decoded
100
	 * @return void
101
	 *
102
	 * @throws UnexpectedValueException
103
	 */
104 2
	protected function validateDecodedResponse( $response_body_decoded )
105
	{
106
		// "data" is quite common in JsonAPI responses, 
107
		// however, we need it as array.
108
109 2
		if (!is_array( $response_body_decoded )):
110
			throw new \UnexpectedValueException("GeocoderAPI response: Expected array");
111
		endif;
112
113 2
		if (!isset( $response_body_decoded['data'] )):
114
			throw new \UnexpectedValueException("GeocoderAPI response: Missing 'data' element");
115
		endif;
116
117 2
		if (!is_array( $response_body_decoded['data'] )):
118
			throw new \UnexpectedValueException("GeocoderAPI response: Element 'data' is not array");
119
		endif;
120
121 2
		if (!isset( $response_body_decoded['data']["attributes"] )):
122
			throw new \UnexpectedValueException("GeocoderAPI response: Missing 'data.attributes' element");
123
		endif;
124
125 2
		if (!is_array( $response_body_decoded['data']["attributes"] )):
126
			throw new \UnexpectedValueException("GeocoderAPI response: Element 'data.attributes' is not array");
127
		endif;
128
129
	}		
130
}