Completed
Push — master ( afaf42...8ac772 )
by Raffael
20:10 queued 16:21
created

AttributeDecorator::decorate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 11
cts 11
cp 1
rs 9.6666
c 0
b 0
f 0
cc 2
crap 2
nc 2
nop 2
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\Filesystem\Node;
13
14
use Balloon\AttributeDecorator\AttributeDecoratorInterface;
15
use Balloon\Filesystem;
16
use Balloon\Filesystem\Acl;
17
use Balloon\Server;
18
use Balloon\Server\AttributeDecorator as RoleAttributeDecorator;
19
use Closure;
20
21
class AttributeDecorator implements AttributeDecoratorInterface
22
{
23
    /**
24
     * Server.
25
     *
26
     * @var Server
27
     */
28
    protected $server;
29
30
    /**
31
     * Filesystem.
32
     *
33
     * @var Filesystem
34
     */
35
    protected $fs;
36
37
    /**
38
     * Acl.
39
     *
40
     * @var Acl
41
     */
42
    protected $acl;
43
44
    /**
45
     * Role decorator.
46
     *
47
     * @var RoleAttributeDecorator
48
     */
49
    protected $role_decorator;
50
51
    /**
52
     * Custom attributes.
53
     *
54
     * @var array
55
     */
56
    protected $custom = [];
57
58
    /**
59
     * Init.
60
     */
61 6
    public function __construct(Server $server, Acl $acl, RoleAttributeDecorator $role_decorator)
62
    {
63 6
        $this->server = $server;
64 6
        $this->acl = $acl;
65 6
        $this->role_decorator = $role_decorator;
66 6
    }
67
68
    /**
69
     * Decorate attributes.
70
     */
71 6
    public function decorate(NodeInterface $node, array $attributes = []): array
72
    {
73 6
        $requested = $attributes;
74 6
        $attributes = $node->getAttributes();
75
76 6
        $attrs = array_merge(
77 6
            $this->getAttributes($node, $attributes),
78 6
            $this->getTimeAttributes($node, $attributes),
79 6
            $this->getTypeAttributes($node, $attributes),
80 6
            $this->custom
81
        );
82
83 6
        if (0 === count($requested)) {
84 2
            return $this->translateAttributes($node, $attrs);
85
        }
86
87 4
        return $this->translateAttributes($node, array_intersect_key($attrs, array_flip($requested)));
88
    }
89
90
    /**
91
     * Add decorator.
92
     */
93 2
    public function addDecorator(string $attribute, Closure $decorator): self
94
    {
95 2
        $this->custom[$attribute] = $decorator;
96
97 2
        return $this;
98
    }
99
100
    /**
101
     * Get Attributes.
102
     */
103 6
    protected function getAttributes(NodeInterface $node, array $attributes): array
104
    {
105 6
        $acl = $this->acl;
106 6
        $server = $this->server;
107 6
        $fs = $this->server->getFilesystem();
108 6
        $decorator = $this->role_decorator;
109
110
        return [
111 6
            'id' => (string) $attributes['_id'],
112 6
            'name' => (string) $attributes['name'],
113 6
            'mime' => (string) $attributes['mime'],
114 6
            'readonly' => (bool) $attributes['readonly'],
115 6
            'directory' => $node instanceof Collection,
116 6
            'meta' => function ($node) {
117 2
                return (object) $node->getMetaAttributes();
118 6
            },
119 6
            'size' => function ($node) {
120 2
                return $node->getSize();
121 6
            },
122 6
            'path' => function ($node) {
123
                try {
124 2
                    return $node->getPath();
125
                } catch (\Exception $e) {
126
                    return null;
127
                }
128 6
            },
129 6
            'parent' => function ($node) {
130 2
                $parent = $node->getParent();
131
132 2
                if (null === $parent || $parent->isRoot()) {
133 2
                    return null;
134
                }
135
136
                return $this->decorate($node->getParent(), ['id', 'name', '_links']);
137 6
            },
138 6
            'access' => function ($node) use ($acl) {
139 2
                return $acl->getAclPrivilege($node);
140 6
            },
141 6
            'acl' => function ($node) use ($attributes) {
142 2
                if ($node->isShareMember() && count($attributes['acl']) > 0) {
143
                    return $node->getAcl();
144
                }
145
146 2
                return null;
147 6
            },
148 6
            'share' => function ($node) use ($fs) {
149 2
                if ($node->isShared() || !$node->isSpecial()) {
150 2
                    return null;
151
                }
152
153
                try {
154
                    return $this->decorate($fs->findNodeById($node->getShareId(true)), ['id', 'name', '_links']);
155
                } catch (\Exception $e) {
156
                    return null;
157
                }
158 6
            },
159 6
            'sharename' => function ($node) {
160 2
                if (!$node->isShared()) {
161 2
                    return null;
162
                }
163
164
                try {
165
                    return $node->getShareName();
166
                } catch (\Exception $e) {
167
                    return null;
168
                }
169 6
            },
170 6
            'shareowner' => function ($node) use ($server, $fs, $decorator) {
171 2
                if (!$node->isSpecial()) {
172 2
                    return null;
173
                }
174
175
                try {
176
                    return $decorator->decorate(
177
                        $server->getUserById($fs->findRawNode($node->getShareId())['owner']),
178
                        ['id', 'name', '_links']
179
                    );
180
                } catch (\Exception $e) {
181
                    return null;
182
                }
183 6
            },
184 6
            'owner' => function ($node) use ($server, $decorator) {
185
                try {
186 2
                    return $decorator->decorate(
187 2
                        $server->getUserById($node->getOwner()),
188
                        ['id', 'name', '_links']
189
                    );
190 2
                } catch (\Exception $e) {
191 2
                    return null;
192
                }
193 6
            },
194 6
            'external_storage' => function ($node) use ($fs, $attributes) {
195 2
                if ($node->getMount() === null || $node instanceof Collection && $node->isMounted()) {
196 2
                    return null;
197
                }
198
199
                return $this->decorate($fs->findNodeById($attributes['storage_reference']), ['id', 'name', '_links']);
200 6
            },
201
        ];
202
    }
203
204
    /**
205
     * Get Attributes.
206
     *
207
     * @param NodeInterface
208
     */
209
    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...
210
    {
211
        return [
212 6
            '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...
213 2
                return $attributes['created']->toDateTime()->format('c');
214 6
            },
215 6
            '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...
216 2
                return $attributes['changed']->toDateTime()->format('c');
217 6
            },
218 6
            '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...
219 2
                if (false === $attributes['deleted']) {
220
                    return null;
221
                }
222
223 2
                return $attributes['deleted']->toDateTime()->format('c');
224 6
            },
225 6
            '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...
226 2
                if (null === $attributes['destroy']) {
227
                    return null;
228
                }
229
230 2
                return $attributes['destroy']->toDateTime()->format('c');
231 6
            },
232
        ];
233
    }
234
235
    /**
236
     * Get Attributes.
237
     */
238 6
    protected function getTypeAttributes(NodeInterface $node, array $attributes): array
239
    {
240 6
        $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...
241 6
        $fs = $this->server->getFilesystem();
242
243 6
        if ($node instanceof File) {
244
            return [
245 4
                'version' => $attributes['version'],
246 4
                'hash' => $attributes['hash'],
247
            ];
248
        }
249
250
        return [
251 3
            'shared' => $node->isShared(),
252 3
            'reference' => $node->isReference(),
253 3
            'filter' => 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...
254 1
                if (null === $attributes['filter']) {
255
                    return null;
256
                }
257
258 1
                return json_decode($attributes['filter'], true);
259 3
            },
260 3
            'mount' => function ($node) use ($fs, $attributes) {
261 1
                $mount = $node->getAttributes()['mount'];
262
263 1
                if (!$node->isMounted() && !$node->isReference()) {
264 1
                    return null;
265
                }
266
267
                if ($node->isReference()) {
268
                    $attributes = $fs->findRawNode($node->getShareId());
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $attributes, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
269
                    if (isset($attributes['mount']) && count($attributes['mount']) > 0) {
270
                        $mount = $attributes['mount'];
271
                        unset($mount['username'], $mount['password']);
272
273
                        return $mount;
274
                    }
275
276
                    return null;
277
                }
278
279
                if (!empty($mount['password'])) {
280
                    unset($mount['password']);
281
                    $mount['has_password'] = true;
282
                }
283
284
                return $mount;
285 3
            },
286
        ];
287
    }
288
289
    /**
290
     * Execute closures.
291
     */
292 6 View Code Duplication
    protected function translateAttributes(NodeInterface $node, array $attributes): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
293
    {
294 6
        foreach ($attributes as $key => &$value) {
295 6
            if ($value instanceof Closure) {
296 4
                $result = $value->call($this, $node);
297
298 4
                if (null === $result) {
299 3
                    unset($attributes[$key]);
300
                } else {
301 4
                    $value = $result;
302
                }
303 4
            } elseif ($value === null) {
304 6
                unset($attributes[$key]);
305
            }
306
        }
307
308 6
        return $attributes;
309
    }
310
}
311