WosClient::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
/**
4
 * PHP Client for DDN Web Object Scalar (WOS) API
5
 *
6
 * @package Wosclient
7
 * @author  Casey McLaughlin <[email protected]>
8
 * @license http://opensource.org/licenses/MIT MIT
9
 * @link    https://github.com/caseyamcl/wosclient
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 *
14
 * ------------------------------------------------------------------
15
 */
16
17
namespace WosClient;
18
19
use GuzzleHttp\Client;
20
use GuzzleHttp\Exception\BadResponseException;
21
use Psr\Http\Message\ResponseInterface;
22
use WosClient\Exception\InvalidResponseException;
23
use WosClient\Exception\WosServerException;
24
25
/**
26
 * WOS Client Implementation for current/latest WOS API
27
 *
28
 * Tested against WOS Version 2.1.1, but should work in newer versions, so
29
 * long as DDN doesn't mess with their API much.
30
 *
31
 * @author Casey McLaughlin <[email protected]>
32
 */
33
class WosClient implements WosClientInterface
34
{
35
    use Helper\ValidateByteRangeTrait;
36
    use Helper\ArrayToMetadataStringTrait;
37
38
    /**
39
     * @var Client
40
     */
41
    private $guzzleClient;
42
43
    /**
44
     * Build a WOS Client from parameters
45
     *
46
     * @param  string $wosUrl
47
     * @param  string $wosPolicy
48
     * @param  array  $guzzleOptions
49
     * @return WosClient
50
     */
51
    public static function build($wosUrl, $wosPolicy = '', array $guzzleOptions = [])
52
    {
53
        $guzzleParams = array_merge_recursive([
54
            'base_uri' => $wosUrl,
55
            'headers'  => [
56
                'x-ddn-policy' => $wosPolicy
57
            ]
58
        ], $guzzleOptions);
59
60
61
        return new static(new Client($guzzleParams));
62
    }
63
64
    /**
65
     * WOS Client constructor
66
     *
67
     * The constructor expects a guzzleClient with the base_url value set, and
68
     * any default options that should be used on all requests.
69
     *
70
     * For convenience, you probably want to set the 'x-ddn-policy' header by
71
     * default.  See the self::build() method above for an example of setting
72
     * this.
73
     *
74
     * @param Client $guzzleClient
75
     */
76
    public function __construct(Client $guzzleClient)
77
    {
78
        if (! isset($guzzleClient->getConfig()['base_uri'])) {
79
            throw new \RuntimeException("Cannot instantiate a WosClient without 'base_uri' set in Guzzle");
80
        }
81
82
        $this->guzzleClient = $guzzleClient;
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88
    public function putObject($data, array $meta = [], $objectId = '', array $options = [])
89
    {
90
        $options = array_merge_recursive([
91
            'body'       => $data,
92
            'headers'    => array_filter([
93
                'x-ddn-meta' => $this->metadataToString($meta),
94
                'x-ddn-oid'  => (string) $objectId
95
            ])
96
        ], $options);
97
98
99
        $resp = $this->sendRequest(
100
            'post',
101
            $objectId ? '/cmd/putoid' : '/cmd/put',
102
            $options
103
        );
104
105
        $this->checkResponse($resp);
106
        return new WosObjectId($resp);
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function getObject($objectId, $byteRange = '', array $options = [])
113
    {
114
        // Add range to options if specified
115
        $options = array_merge_recursive([
116
            'headers' => array_filter([
117
                'range' => $byteRange ? ('bytes=' . $this->validateByteRange($byteRange)) : ''
118
            ])
119
        ], $options);
120
121
        $resp = $this->sendRequest('get', '/objects/' . (string) $objectId, $options);
122
123
        $this->checkResponse($resp);
124
        return new WosObject($resp);
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    public function getMetadata($objectId, array $options = [])
131
    {
132
        $resp = $this->sendRequest('head', '/objects/' . $objectId, $options);
133
        $this->checkResponse($resp);
134
        return new WosObjectMetadata($resp);
135
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    public function deleteObject($objectId, array $options = [])
142
    {
143
        // OID is sent in header, not in URI
144
        $options = array_merge_recursive([
145
            'headers' => [
146
                'x-ddn-oid' => (string) $objectId
147
            ]
148
        ], $options);
149
150
        $resp = $this->sendRequest('post', '/cmd/delete', $options);
151
        $this->checkResponse($resp);
152
    }
153
154
    /**
155
     * {@inheritdoc}
156
     */
157
    public function reserveObject(array $options = [])
158
    {
159
        $resp = $this->sendRequest('post', '/cmd/reserve', $options);
160
161
        $this->checkResponse($resp);
162
        return new WosObjectId($resp);
163
    }
164
165
    /**
166
     * @return Client
167
     */
168
    public function getHttpClient()
169
    {
170
        return $this->guzzleClient;
171
    }
172
173
    /**
174
     * Perform a request
175
     *
176
     * @param  string $method
177
     * @param  string $path
178
     * @param  array  $options
179
     * @return ResponseInterface
180
     */
181
    public function sendRequest($method, $path, array $options = [])
182
    {
183
        try {
184
            return $this->guzzleClient->request($method, $path, $options);
185
        } catch (BadResponseException $e) {
186
            throw ($e->getResponse()->hasHeader('x-ddn-status'))
187
                ? new WosServerException((int) $e->getResponse()->getHeaderLine('x-ddn-status'))
188
                : $e;
189
        }
190
    }
191
192
    /**
193
     * Process a response
194
     *
195
     * Ensure that this is a valid response, and
196
     * convert any DDN errors into appropriate exceptions
197
     *
198
     * @param ResponseInterface $response
199
     */
200
    private function checkResponse(ResponseInterface $response)
201
    {
202
        if (! $response->hasHeader('x-ddn-status')) {
203
            throw new InvalidResponseException('x-ddn-status');
204
        }
205
206
        $headerLine = $response->getHeaderLine('x-ddn-status');
207
        if ($headerLine{0} !== '0') {
208
            throw new WosServerException((int) $response->getHeaderLine('x-ddn-status'));
209
        }
210
    }
211
}
212