Passed
Push — master ( b8e2b8...5d024f )
by Jonathan
17:35
created

PostTrait::getDocumentThumbnails()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 35
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 19
c 1
b 0
f 0
dl 0
loc 35
ccs 20
cts 20
cp 1
rs 9.6333
cc 3
nc 2
nop 5
crap 3
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * ReportingCloud PHP SDK
6
 *
7
 * PHP SDK for ReportingCloud Web API. Authored and supported by Text Control GmbH.
8
 *
9
 * @link      https://www.reporting.cloud to learn more about ReportingCloud
10
 * @link      https://git.io/Jejj2 for the canonical source repository
11
 * @license   https://git.io/Jejjr
12
 * @copyright © 2021 Text Control GmbH
13
 */
14
15
namespace TxTextControl\ReportingCloud;
16
17
use Ctw\Http\HttpMethod;
18
use Ctw\Http\HttpStatus;
19
use GuzzleHttp\RequestOptions;
20
use Psr\Http\Message\ResponseInterface;
21
use TxTextControl\ReportingCloud\Assert\Assert;
22
use TxTextControl\ReportingCloud\Exception\InvalidArgumentException;
23
use TxTextControl\ReportingCloud\Exception\RuntimeException;
24
use TxTextControl\ReportingCloud\Filter\Filter;
25
use TxTextControl\ReportingCloud\PropertyMap\AbstractPropertyMap as PropertyMap;
26
use TxTextControl\ReportingCloud\PropertyMap\ModifiedDocument as ModifiedDocumentPropertyMap;
27
use TxTextControl\ReportingCloud\PropertyMap\TrackedChanges as TrackedChangesPropertyMap;
28
use TxTextControl\ReportingCloud\Stdlib\FileUtils;
29
30
/**
31
 * Trait PostTrait
32
 *
33
 * @package TxTextControl\ReportingCloud
34
 * @author  Jonathan Maron (@JonathanMaron)
35
 */
36
trait PostTrait
37
{
38
    // <editor-fold desc="Abstract methods">
39
40
    /**
41
     * Construct URI with version number
42
     *
43
     * @param string $uri URI
44
     *
45
     * @return string
46
     */
47
    abstract protected function uri(string $uri): string;
48
49
    /**
50
     * Request the URI with options
51
     *
52
     * @param string $method  HTTP method
53
     * @param string $uri     URI
54
     * @param array  $options Options
55
     *
56
     * @return ResponseInterface
57
     * @throws RuntimeException
58
     */
59
    abstract protected function request(string $method, string $uri, array $options): ResponseInterface;
60
61
    /**
62
     * Using passed findAndReplaceData associative array (key-value), build array for backend (list of string arrays)
63
     *
64
     * @param array $array FindAndReplaceData array
65
     *
66
     * @return array
67
     */
68
    abstract protected function buildFindAndReplaceDataArray(array $array): array;
69
70
    /**
71
     * Using passed mergeSettings array, build array for backend
72
     *
73
     * @param array $array MergeSettings array
74
     *
75
     * @return array
76
     */
77
    abstract protected function buildMergeSettingsArray(array $array): array;
78
79
    /**
80
     * Using passed documentsData array, build array for backend
81
     *
82
     * @param array $array AppendDocument array
83
     *
84
     * @return array
85
     */
86
    abstract protected function buildDocumentsArray(array $array): array;
87
88
    /**
89
     * Using passed documentsSettings array, build array for backend
90
     *
91
     * @param array $array
92
     *
93
     * @return array
94
     */
95
    abstract protected function buildDocumentSettingsArray(array $array): array;
96
97
    /**
98
     * Using the passed propertyMap, recursively build array
99
     *
100
     * @param array       $array       Array
101
     * @param PropertyMap $propertyMap PropertyMap
102
     *
103
     * @return array
104
     */
105
    abstract protected function buildPropertyMapArray(array $array, PropertyMap $propertyMap): array;
106
107
    // </editor-fold>
108
109
    // <editor-fold desc="Methods">
110
111
    /**
112
     * Upload a base64 encoded template to template storage
113
     *
114
     * @param string $data         Template encoded as base64
115
     * @param string $templateName Template name
116
     *
117
     * @return bool
118
     * @throws InvalidArgumentException
119
     */
120 24
    public function uploadTemplateFromBase64(string $data, string $templateName): bool
121
    {
122 24
        Assert::assertBase64Data($data);
123 24
        Assert::assertTemplateName($templateName);
124
125 12
        $query = [
126 24
            'templateName' => $templateName,
127
        ];
128
129 24
        $result = $this->post('/templates/upload', $query, $data, HttpStatus::STATUS_CREATED);
130
131 24
        return null === $result;
132
    }
133
134
    /**
135
     * Upload a template to template storage
136
     *
137
     * @param string $templateFilename Template name
138
     *
139
     * @return bool
140
     * @throws InvalidArgumentException
141
     */
142 30
    public function uploadTemplate(string $templateFilename): bool
143
    {
144 30
        Assert::assertTemplateExtension($templateFilename);
145 24
        Assert::assertFilenameExists($templateFilename);
146
147 22
        $templateName = basename($templateFilename);
148
149 22
        $data = FileUtils::read($templateFilename, true);
150
151 22
        return $this->uploadTemplateFromBase64($data, $templateName);
152
    }
153
154
    /**
155
     * Convert a document on the local file system to a different format
156
     *
157
     * @param string $documentFilename Document filename
158
     * @param string $returnFormat     Return format
159
     *
160
     * @return string
161
     * @throws InvalidArgumentException
162
     */
163 14
    public function convertDocument(string $documentFilename, string $returnFormat): string
164
    {
165 14
        Assert::assertDocumentExtension($documentFilename);
166 8
        Assert::assertFilenameExists($documentFilename);
167 6
        Assert::assertReturnFormat($returnFormat);
168
169 2
        $query  = [
170 4
            'returnFormat' => $returnFormat,
171
        ];
172
173 4
        $data   = FileUtils::read($documentFilename, true);
174
175 4
        $result = (string) $this->post('/document/convert', $query, $data, HttpStatus::STATUS_OK);
176
177 4
        return (string) base64_decode($result, true);
178
    }
179
180
    /**
181
     * Merge data into a template and return an array of binary data.
182
     * Each record in the array is the binary data of one document
183
     *
184
     * @param array<int|string, array|bool|int|string> $mergeData        Array of merge data
185
     * @param string                                   $returnFormat     Return format
186
     * @param string                                   $templateName     Template name
187
     * @param string                                   $templateFilename Template filename on local file system
188
     * @param bool                                     $append           Append flag
189
     * @param array<string, bool|int|string>           $mergeSettings    Array of merge settings
190
     *
191
     * @return array<int, string>
192
     * @throws InvalidArgumentException
193
     */
194 24
    public function mergeDocument(
195
        array $mergeData,
196
        string $returnFormat,
197
        string $templateName = '',
198
        string $templateFilename = '',
199
        bool $append = false,
200
        array $mergeSettings = []
201
    ): array {
202
203 24
        $query = [];
204 24
        $json  = [];
205
206 24
        $json['mergeData'] = $mergeData;
207
208 24
        Assert::assertReturnFormat($returnFormat);
209 22
        $query['returnFormat'] = $returnFormat;
210
211 22
        if (strlen($templateName) > 0) {
212 4
            Assert::assertTemplateName($templateName);
213 2
            $query['templateName'] = $templateName;
214
        }
215
216 20
        if (strlen($templateFilename) > 0) {
217 18
            Assert::assertTemplateExtension($templateFilename);
218 12
            Assert::assertFilenameExists($templateFilename);
219 10
            $json['template'] = FileUtils::read($templateFilename, true);
220
        }
221
222 12
        if ($append) {
223
            //Assert::assertBoolean($append);
224
            $query['append'] = Filter::filterBooleanToString($append);
225
        }
226
227 12
        if (count($mergeSettings) > 0) {
228 10
            $json['mergeSettings'] = $this->buildMergeSettingsArray($mergeSettings);
229
        }
230
231 6
        $result = $this->post('/document/merge', $query, $json, HttpStatus::STATUS_OK);
232
233 6
        if (is_array($result)) {
234 6
            foreach ($result as $key => $value) {
235 6
                $value = base64_decode($value, true);
236 6
                assert(is_string($value));
237 6
                $result[$key] = $value;
238
            }
239
        }
240
241 6
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result could return the type string which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
242
    }
243
244
    /**
245
     * Combine documents by appending them, divided by a new section, paragraph or nothing
246
     *
247
     * @param array<int|string, array|bool|int|string> $documentsData
248
     * @param string                                   $returnFormat
249
     * @param array<string, bool|int|string>           $documentSettings
250
     *
251
     * @return string
252
     * @throws InvalidArgumentException
253
     */
254 2
    public function appendDocument(
255
        array $documentsData,
256
        string $returnFormat,
257
        array $documentSettings = []
258
    ): string {
259
260 2
        $query = [];
261 2
        $json  = [];
262
263 2
        $json['documents'] = $this->buildDocumentsArray($documentsData);
264
265 2
        Assert::assertReturnFormat($returnFormat);
266 2
        $query['returnFormat'] = $returnFormat;
267
268 2
        if (count($documentSettings) > 0) {
269 2
            $json['documentSettings'] = $this->buildDocumentSettingsArray($documentSettings);
270
        }
271
272 2
        $result = (string) $this->post('/document/append', $query, $json, HttpStatus::STATUS_OK);
273
274 2
        return (string) base64_decode($result, true);
275
    }
276
277
    /**
278
     * Perform find and replace in document and return binary data.
279
     *
280
     * @param array<string, string>          $findAndReplaceData Array of find and replace data
281
     * @param string                         $returnFormat       Return format
282
     * @param string                         $templateName       Template name
283
     * @param string                         $templateFilename   Template filename on local file system
284
     * @param array<string, bool|int|string> $mergeSettings      Array of merge settings
285
     *
286
     * @return string
287
     * @throws InvalidArgumentException
288
     */
289 20
    public function findAndReplaceDocument(
290
        array $findAndReplaceData,
291
        string $returnFormat,
292
        string $templateName = '',
293
        string $templateFilename = '',
294
        array $mergeSettings = []
295
    ): string {
296 20
        $query = [];
297 20
        $json  = [];
298
299 20
        $json['findAndReplaceData'] = $this->buildFindAndReplaceDataArray($findAndReplaceData);
300
301 20
        Assert::assertReturnFormat($returnFormat);
302 18
        $query['returnFormat'] = $returnFormat;
303
304 18
        if (strlen($templateName) > 0) {
305 4
            Assert::assertTemplateName($templateName);
306 2
            $query['templateName'] = $templateName;
307
        }
308
309 16
        if (strlen($templateFilename) > 0) {
310 14
            Assert::assertTemplateExtension($templateFilename);
311 8
            Assert::assertFilenameExists($templateFilename);
312 6
            $json['template'] = FileUtils::read($templateFilename, true);
313
        }
314
315 8
        if (count($mergeSettings) > 0) {
316 8
            $json['mergeSettings'] = $this->buildMergeSettingsArray($mergeSettings);
317
        }
318
319 4
        $result = (string) $this->post('/document/findandreplace', $query, $json, HttpStatus::STATUS_OK);
320
321 4
        return (string) base64_decode($result, true);
322
    }
323
324
    /**
325
     * Generate a thumbnail image per page of specified document filename.
326
     * Return an array of binary data with each record containing one thumbnail.
327
     *
328
     * @param string $documentFilename Document filename
329
     * @param int    $zoomFactor       Zoom factor
330
     * @param int    $fromPage         From page
331
     * @param int    $toPage           To page
332
     * @param string $imageFormat      Image format
333
     *
334
     * @throws InvalidArgumentException
335
     * @return array<int, string>
336
     */
337 2
    public function getDocumentThumbnails(
338
        string $documentFilename,
339
        int $zoomFactor,
340
        int $fromPage,
341
        int $toPage,
342
        string $imageFormat
343
    ): array {
344
345 2
        Assert::assertDocumentThumbnailExtension($documentFilename);
346 2
        Assert::assertFilenameExists($documentFilename);
347 2
        Assert::assertZoomFactor($zoomFactor);
348 2
        Assert::assertPage($fromPage);
349 2
        Assert::assertPage($toPage);
350 2
        Assert::assertImageFormat($imageFormat);
351
352 1
        $query = [
353 2
            'zoomFactor'   => $zoomFactor,
354 2
            'fromPage'     => $fromPage,
355 2
            'toPage'       => $toPage,
356 2
            'imageFormat'  => $imageFormat,
357
        ];
358
359 2
        $data   = FileUtils::read($documentFilename, true);
360
361 2
        $result = $this->post('/document/thumbnails', $query, $data, HttpStatus::STATUS_OK);
362
363 2
        if (is_array($result)) {
364 2
            foreach ($result as $key => $value) {
365 2
                $value = base64_decode($value, true);
366 2
                assert(is_string($value));
367 2
                $result[$key] = $value;
368
            }
369
        }
370
371 2
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result could return the type string which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
372
    }
373
374
    /**
375
     * Return the tracked changes in a document.
376
     *
377
     * @param string $documentFilename Document filename
378
     *
379
     * @throws InvalidArgumentException
380
     * @return array<int|string, array|bool|int|string>
381
     */
382 2
    public function getTrackedChanges(
383
        string $documentFilename
384
    ): array {
385 2
        $ret = [];
386
387 2
        $propertyMap = new TrackedChangesPropertyMap();
388
389 2
        Assert::assertDocumentExtension($documentFilename);
390 2
        Assert::assertFilenameExists($documentFilename);
391
392 2
        $data   = FileUtils::read($documentFilename, true);
393
394 2
        $result = $this->post('/processing/review/trackedchanges', [], $data, HttpStatus::STATUS_OK);
395
396 2
        if (is_array($result)) {
397 2
            $ret = $this->buildPropertyMapArray($result, $propertyMap);
398 2
            array_walk($ret, function (array &$record): void {
399 2
                $key = 'change_time';
400 2
                if (isset($record[$key])) {
401
                    //@todo [20190902] return value of backend DateTime in Zulu timezone
402
                    //Assert::assertDateTime($record[$key]);
403 2
                    $record[$key] = Filter::filterDateTimeToTimestamp($record[$key]);
404
                }
405 2
            });
406
        }
407
408 2
        return $ret;
409
    }
410
411
    /**
412
     * Removes a specific tracked change and returns the resulting document.
413
     *
414
     * @param string $documentFilename Document filename
415
     * @param int $id                  The ID of the tracked change that needs to be removed
416
     * @param bool $accept             Specifies whether the tracked change should be accepted or not (reject)
417
     *
418
     * @throws InvalidArgumentException
419
     * @return array<int|string, array|bool|int|string>
420
     *
421
     */
422 2
    public function removeTrackedChange(
423
        string $documentFilename,
424
        int $id,
425
        bool $accept
426
    ): array {
427 2
        $ret = [];
428
429 2
        $propertyMap = new ModifiedDocumentPropertyMap();
430
431 2
        Assert::assertDocumentExtension($documentFilename);
432 2
        Assert::assertFilenameExists($documentFilename);
433
434 1
        $query  = [
435 2
            'id'     => $id,
436 2
            'accept' => Filter::filterBooleanToString($accept),
437
        ];
438
439 2
        $data   = FileUtils::read($documentFilename, true);
440
441 2
        $result = $this->post('/processing/review/removetrackedchange', $query, $data, HttpStatus::STATUS_OK);
442
443 2
        if (is_array($result)) {
444 2
            $ret = $this->buildPropertyMapArray($result, $propertyMap);
445 2
            $key = 'document';
446 2
            if (isset($ret[$key]) && is_string($ret[$key])) {
447 2
                $ret[$key] = base64_decode($ret[$key], true);
448
            }
449
        }
450
451 2
        return $ret;
452
    }
453
454
    /**
455
     * Execute a POST request via REST client
456
     *
457
     * @param string                            $uri        URI
458
     * @param array<string, int|string>|array[] $query      Query
459
     * @param mixed                             $json       JSON
460
     * @param int                               $statusCode Required HTTP status code for response
461
     *
462
     * @return mixed
463
     */
464 42
    private function post(
465
        string $uri,
466
        array $query = [],
467
        $json = '',
468
        int $statusCode = 0
469
    ) {
470
471 42
        $ret = '';
472
473 21
        $options = [
474 42
            RequestOptions::QUERY => $query,
475 42
            RequestOptions::JSON  => $json,
476
        ];
477
478 42
        $response = $this->request(HttpMethod::METHOD_POST, $this->uri($uri), $options);
479
480 42
        if ($statusCode === $response->getStatusCode()) {
481 42
            $ret = json_decode($response->getBody()->getContents(), true);
482
        }
483
484 42
        return $ret;
485
    }
486
487
    // </editor-fold>
488
}
489