PostTrait   A
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 408
Duplicated Lines 0 %

Test Coverage

Coverage 96.1%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 38
eloc 140
c 1
b 0
f 0
dl 0
loc 408
ccs 148
cts 154
cp 0.961
rs 9.36

10 Methods

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