PostTrait::findAndReplaceDocument()   B
last analyzed

Complexity

Conditions 7
Paths 24

Size

Total Lines 40
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 7.0052

Importance

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