Passed
Pull Request — master (#38)
by Dante
03:55 queued 01:16
created

ApiFormatterComponent   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 47
c 1
b 0
f 0
dl 0
loc 113
rs 10
wmc 16

4 Methods

Rating   Name   Duplication   Size   Complexity  
A embedIncluded() 0 27 5
A extractFromIncluded() 0 11 2
A addObjectsStream() 0 28 6
A addIncluded() 0 12 3
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * API Formatter
6
 *
7
 * Copyright 2021 Atlas Srl
8
 */
9
namespace BEdita\WebTools\Controller\Component;
10
11
use Cake\Collection\Collection;
12
use Cake\Controller\Component;
13
use Cake\I18n\Number;
14
use Cake\Utility\Hash;
15
16
/**
17
 * Component class to format API response data.
18
 */
19
class ApiFormatterComponent extends Component
20
{
21
    /**
22
     * Add 'stream' to each object in response data, when available in included data.
23
     *
24
     * @param array $response The response data
25
     * @return array
26
     */
27
    public function addObjectsStream(array $response): array
28
    {
29
        $objects = (array)Hash::get($response, 'data');
30
        if (empty($objects)) {
31
            return $response;
32
        }
33
        $included = (array)Hash::get($response, 'included');
34
        if (empty($included)) {
35
            return $response;
36
        }
37
        $included = collection($included);
38
        /** @var array $object */
39
        foreach ($objects as &$object) {
40
            if (!Hash::check($object, 'relationships.streams.data')) {
41
                continue;
42
            }
43
            $relationData = (array)Hash::get($object, 'relationships.streams.data');
44
            $streams = $this->extractFromIncluded($included, $relationData);
45
            $stream = $streams[0];
46
            if (Hash::check($stream, 'meta.file_size')) {
47
                $size = (int)Hash::get($stream, 'meta.file_size');
48
                $stream['meta']['file_size'] = Number::toReadableSize($size);
49
            }
50
            $object['stream'] = $stream;
51
        }
52
        $response['data'] = $objects;
53
54
        return $response;
55
    }
56
57
    /**
58
     * Embed included data into relationships.
59
     *
60
     * @param array $response The response from API
61
     * @return array
62
     */
63
    public function embedIncluded(array $response): array
64
    {
65
        $data = (array)Hash::get($response, 'data');
66
        if (empty($data)) {
67
            return $data;
68
        }
69
70
        $included = (array)Hash::get($response, 'included');
71
        if (empty($included)) {
72
            return $response;
73
        }
74
75
        $included = collection($included);
76
        if (!Hash::numeric(array_keys($data))) {
77
            $response['data'] = $this->addIncluded($data, $included);
78
79
            return $response;
80
        }
81
82
        foreach ($data as &$d) {
83
            $d = $this->addIncluded($d, $included);
84
        }
85
        unset($d);
86
87
        $response['data'] = $data;
88
89
        return $response;
90
    }
91
92
    /**
93
     * Add included data to main resource.
94
     *
95
     * @param array $resource The resource.
96
     * @param \Cake\Collection\Collection $included The included collection.
97
     * @return array
98
     */
99
    protected function addIncluded(array $resource, Collection $included): array
100
    {
101
        foreach ($resource['relationships'] as &$relation) {
102
            if (empty($relation['data'])) {
103
                continue;
104
            }
105
106
            $relation['data'] = $this->extractFromIncluded($included, (array)$relation['data']);
107
        }
108
        unset($relation);
109
110
        return $resource;
111
    }
112
113
    /**
114
     * Extract items from included starting from $relationship data.
115
     *
116
     * @param \Cake\Collection\Collection $included The included collection
117
     * @param array $relationshipData Array of relationship data.
118
     *                                Every item must contain 'type' and 'id'.
119
     * @return array
120
     */
121
    protected function extractFromIncluded(Collection $included, array $relationshipData): array
122
    {
123
        foreach ($relationshipData as &$data) {
124
            $data = (array)$included->firstMatch([
125
                'type' => $data['type'],
126
                'id' => $data['id'],
127
            ]);
128
        }
129
        unset($data);
130
131
        return $relationshipData;
132
    }
133
}
134