Completed
Pull Request — master (#219)
by Raffael
46:26
created

AttributeDecorator   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 283
Duplicated Lines 6.36 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 78.42%

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 4
dl 18
loc 283
ccs 109
cts 139
cp 0.7842
rs 9.6
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getTimeAttributes() 0 25 3
A __construct() 0 6 1
A decorate() 0 18 2
A addDecorator() 0 6 1
C getAttributes() 0 93 14
B getTypeAttributes() 0 50 9
A translateAttributes() 18 18 5

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
        ];
195
    }
196
197
    /**
198
     * Get Attributes.
199
     *
200
     * @param NodeInterface
201
     */
202
    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...
203
    {
204
        return [
205 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...
206 2
                return $attributes['created']->toDateTime()->format('c');
207 6
            },
208 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...
209 2
                return $attributes['changed']->toDateTime()->format('c');
210 6
            },
211 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...
212 2
                if (false === $attributes['deleted']) {
213
                    return null;
214
                }
215
216 2
                return $attributes['deleted']->toDateTime()->format('c');
217 6
            },
218 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...
219 2
                if (null === $attributes['destroy']) {
220
                    return null;
221
                }
222
223 2
                return $attributes['destroy']->toDateTime()->format('c');
224 6
            },
225
        ];
226
    }
227
228
    /**
229
     * Get Attributes.
230
     */
231 6
    protected function getTypeAttributes(NodeInterface $node, array $attributes): array
232
    {
233 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...
234 6
        $fs = $this->server->getFilesystem();
235
236 6
        if ($node instanceof File) {
237
            return [
238 4
                'version' => $attributes['version'],
239 4
                'hash' => $attributes['hash'],
240
            ];
241
        }
242
243
        return [
244 3
            'shared' => $node->isShared(),
245 3
            'reference' => $node->isReference(),
246 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...
247 1
                if (null === $attributes['filter']) {
248
                    return null;
249
                }
250
251 1
                return json_decode($attributes['filter'], true);
252 3
            },
253 3
            'mount' => function ($node) use ($fs, $attributes) {
254 1
                $mount = $node->getAttributes()['mount'];
255
256 1
                if (!$node->isMounted() && !$node->isReference()) {
257 1
                    return null;
258
                }
259
260
                if ($node->isReference()) {
261
                    $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...
262
                    if (isset($attributes['mount']) && count($attributes['mount']) > 0) {
263
                        $mount = $attributes['mount'];
264
                        unset($mount['username'], $mount['password']);
265
266
                        return $mount;
267
                    }
268
269
                    return null;
270
                }
271
272
                if (!empty($mount['password'])) {
273
                    unset($mount['password']);
274
                    $mount['has_password'] = true;
275
                }
276
277
                return $mount;
278 3
            },
279
        ];
280
    }
281
282
    /**
283
     * Execute closures.
284
     */
285 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...
286
    {
287 6
        foreach ($attributes as $key => &$value) {
288 6
            if ($value instanceof Closure) {
289 4
                $result = $value->call($this, $node);
290
291 4
                if (null === $result) {
292 3
                    unset($attributes[$key]);
293
                } else {
294 4
                    $value = $result;
295
                }
296 4
            } elseif ($value === null) {
297 6
                unset($attributes[$key]);
298
            }
299
        }
300
301 6
        return $attributes;
302
    }
303
}
304