Completed
Branch dev (d5d70c)
by Raffael
11:00
created

NodeDecorator::getAttributes()   B

Complexity

Conditions 8
Paths 1

Size

Total Lines 61
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 61
rs 7.0047
c 0
b 0
f 0
cc 8
eloc 40
nc 1
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * balloon
7
 *
8
 * @copyright   Copryright (c) 2012-2018 gyselroth GmbH (https://gyselroth.com)
9
 * @license     GPL-3.0 https://opensource.org/licenses/GPL-3.0
10
 */
11
12
namespace Balloon\App\Api\v1\AttributeDecorator;
13
14
use Balloon\Filesystem;
15
use Balloon\Filesystem\Acl;
16
use Balloon\Filesystem\Node\Collection;
17
use Balloon\Filesystem\Node\File;
18
use Balloon\Filesystem\Node\NodeInterface;
19
use Balloon\Server;
20
use Closure;
21
use MongoDB\BSON\UTCDateTime;
22
use stdClass;
23
24
class NodeDecorator
25
{
26
    /**
27
     * Server.
28
     *
29
     * @var Server
30
     */
31
    protected $server;
32
33
    /**
34
     * Filesystem.
35
     *
36
     * @var Filesystem
37
     */
38
    protected $fs;
39
40
    /**
41
     * Acl.
42
     *
43
     * @var Acl
44
     */
45
    protected $acl;
46
47
    /**
48
     * Custom attributes.
49
     *
50
     * @var array
51
     */
52
    protected $custom = [];
53
54
    /**
55
     * Init.
56
     *
57
     * @param Server $server
58
     * @param Acl    $acl
59
     */
60
    public function __construct(Server $server, Acl $acl)
61
    {
62
        $this->server = $server;
63
        $this->acl = $acl;
64
    }
65
66
    /**
67
     * Decorate attributes.
68
     *
69
     * @param NodeInterface $node
70
     * @param array         $attributes
71
     *
72
     * @return array
73
     */
74
    public function decorate(NodeInterface $node, array $attributes = []): array
75
    {
76
        $requested = $this->parseAttributes($attributes);
77
        $attributes = $node->getAttributes();
78
79
        $attrs = array_merge(
80
            $this->getAttributes($node, $attributes),
81
            $this->getTimeAttributes($node, $attributes),
82
            $this->getTypeAttributes($node, $attributes),
83
            $this->custom
84
        );
85
86
        if (0 === count($requested)) {
87
            return $this->translateAttributes($node, $attrs);
88
        }
89
90
        return $this->translateAttributes($node, array_intersect_key($attrs, array_flip($requested)));
91
    }
92
93
    /**
94
     * Add decorator.
95
     *
96
     * @param string  $attribute
97
     * @param Closure $decorator
98
     *
99
     * @return AttributeDecorator
100
     */
101
    public function addDecorator(string $attribute, Closure $decorator): self
102
    {
103
        $this->custom[$attribute] = $decorator;
104
105
        return $this;
106
    }
107
108
    /**
109
     * Parse v1 attribute filter requests.
110
     *
111
     * @param array
112
     *
113
     * @return array
114
     */
115
    protected function parseAttributes(array $attributes): array
116
    {
117
        foreach ($attributes as &$attribute) {
118
            $parts = explode('.', $attribute);
119
            $attribute = $parts[0];
120
        }
121
122
        return $attributes;
123
    }
124
125
    /**
126
     * Get Attributes.
127
     *
128
     * @param NodeInterface
129
     *
130
     * @return array
131
     */
132
    protected function getAttributes(NodeInterface $node, array $attributes): array
133
    {
134
        $acl = $this->acl;
135
        $server = $this->server;
136
        $fs = $this->server->getFilesystem();
137
138
        return [
139
            'id' => (string) $attributes['_id'],
140
            'name' => (string) $attributes['name'],
141
            'mime' => (string) $attributes['mime'],
142
            'readonly' => (bool) $attributes['readonly'],
143
            'directory' => $node instanceof Collection,
144
            'meta' => function ($node) {
145
                return (object) $node->getMetaAttributes();
146
            },
147
            'size' => function ($node) {
148
                return $node->getSize();
149
            },
150
            'path' => function ($node) {
151
                try {
152
                    return $node->getPath();
153
                } catch (\Exception $e) {
154
                    return null;
155
                }
156
            },
157
            'parent' => function ($node) {
158
                $id = $node->getAttributes()['parent'];
159
160
                if (null === $id) {
161
                    return null;
162
                }
163
164
                return (string) $id;
165
            },
166
            'access' => function ($node) use ($acl) {
167
                return $acl->getAclPrivilege($node);
168
            },
169
            'share' => function ($node) {
170
                if ($node->isShared() || !$node->isSpecial()) {
171
                    return null;
172
                }
173
174
                try {
175
                    return $this->decorate($node->getShareNode(), ['id', 'name', '_links']);
176
                } catch (\Exception $e) {
177
                    return null;
178
                }
179
            },
180
            'shareowner' => function ($node) use ($server, $fs) {
181
                if (!$node->isSpecial()) {
182
                    return null;
183
                }
184
185
                try {
186
                    return $server->getUserById($fs->findRawNode($node->getShareId())['owner'])->getUsername();
187
                } catch (\Exception $e) {
188
                    return null;
189
                }
190
            },
191
        ];
192
    }
193
194
    /**
195
     * Convert UTCDateTime to unix ts.
196
     *
197
     * @param UTCDateTime $date
198
     *
199
     * @return stdClass
200
     */
201
    protected function dateTimeToUnix(?UTCDateTime $date): ?stdClass
202
    {
203
        if (null === $date) {
204
            return null;
205
        }
206
207
        $date = $date->toDateTime();
208
        $ts = new stdClass();
209
        $ts->sec = $date->format('U');
210
        $ts->usec = $date->format('u');
211
212
        return $ts;
213
    }
214
215
    /**
216
     * Get Attributes.
217
     *
218
     * @param NodeInterface
219
     * @param array $attributes
220
     *
221
     * @return array
222
     */
223
    protected function getTimeAttributes(NodeInterface $node, array $attributes): array
0 ignored issues
show
Unused Code introduced by
The parameter $node is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
224
    {
225
        return [
226
            'created' => function ($node) use ($attributes) {
0 ignored issues
show
Unused Code introduced by
The parameter $node is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
227
                return $this->dateTimeToUnix($attributes['created']);
228
            },
229
            'changed' => function ($node) use ($attributes) {
0 ignored issues
show
Unused Code introduced by
The parameter $node is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
230
                return $this->dateTimeToUnix($attributes['changed']);
231
            },
232
            'deleted' => function ($node) use ($attributes) {
0 ignored issues
show
Unused Code introduced by
The parameter $node is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
233
                if (false === $attributes['deleted']) {
234
                    return false;
235
                }
236
237
                return $this->dateTimeToUnix($attributes['destroy']);
238
            },
239
            'destroy' => function ($node) use ($attributes) {
0 ignored issues
show
Unused Code introduced by
The parameter $node is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
240
                if (null === $attributes['destroy']) {
241
                    return false;
242
                }
243
244
                return $this->dateTimeToUnix($attributes['destroy']);
245
            },
246
        ];
247
    }
248
249
    /**
250
     * Get Attributes.
251
     *
252
     * @param NodeInterface
253
     * @param array $attributes
254
     *
255
     * @return array
256
     */
257
    protected function getTypeAttributes(NodeInterface $node, array $attributes): array
258
    {
259
        $server = $this->server;
0 ignored issues
show
Unused Code introduced by
$server is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
260
        $fs = $this->server->getFilesystem();
0 ignored issues
show
Unused Code introduced by
$fs is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
261
262
        if ($node instanceof File) {
263
            return [
264
                'version' => $attributes['version'],
265
                'hash' => $attributes['hash'],
266
            ];
267
        }
268
269
        return [
270
            'reference' => $node->isReference(),
271
        ];
272
    }
273
274
    /**
275
     * Execute closures.
276
     *
277
     * @param NodeInterface
278
     * @param array $attributes
279
     *
280
     * @return array
281
     */
282
    protected function translateAttributes(NodeInterface $node, array $attributes): array
283
    {
284
        foreach ($attributes as $key => &$value) {
285
            if ($value instanceof Closure) {
286
                $result = $value->call($this, $node);
287
288
                if (null === $result) {
289
                    unset($attributes[$key]);
290
                } else {
291
                    $value = $result;
292
                }
293
            } elseif ($value === null) {
294
                unset($attributes[$key]);
295
            }
296
        }
297
298
        return $attributes;
299
    }
300
}
301