IndexObject   A
last analyzed

Complexity

Total Complexity 42

Size/Duplication

Total Lines 298
Duplicated Lines 0 %

Coupling/Cohesion

Components 5
Dependencies 1

Importance

Changes 0
Metric Value
wmc 42
lcom 5
cbo 1
dl 0
loc 298
rs 9.0399
c 0
b 0
f 0

27 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 19 2
A getRelativePath() 0 4 1
A getBasename() 0 6 2
A getType() 0 4 1
A getTypeName() 0 4 1
A isDirectory() 0 4 1
A isFile() 0 4 1
A isLink() 0 4 1
A getMtime() 0 4 1
A getCtime() 0 4 1
A setCtime() 0 6 1
A getPermissions() 0 4 1
A getPermissionsString() 0 4 1
A getSize() 0 4 1
A getInode() 0 4 1
A getLinkTarget() 0 4 1
A getHashes() 0 4 1
A getBlobId() 0 4 1
A setBlobId() 0 8 1
B equals() 0 25 7
A offsetExists() 0 4 1
A offsetGet() 0 6 1
A offsetSet() 0 4 1
A offsetUnset() 0 4 1
A __clone() 0 7 2
B __toString() 0 30 7
A getTypeNameMap() 0 8 1

How to fix   Complexity   

Complex Class

Complex classes like IndexObject often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use IndexObject, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Storeman\Index;
4
5
use Storeman\FilesystemUtility;
6
use Storeman\Hash\HashContainer;
7
8
/**
9
 * An index object is the representation of one of this filesystem primitives contained in the index.
10
 */
11
class IndexObject implements \ArrayAccess
12
{
13
    public const TYPE_DIR = 1;
14
    public const TYPE_FILE = 2;
15
    public const TYPE_LINK = 3;
16
17
    public const CMP_IGNORE_BLOBID = 1;
18
    public const CMP_IGNORE_INODE = 2;
19
    public const CMP_IGNORE_CTIME = 4;
20
21
22
    /**
23
     * @var string
24
     */
25
    protected $relativePath;
26
27
    /**
28
     * @var int
29
     */
30
    protected $type;
31
32
    /**
33
     * @var float
34
     */
35
    protected $mtime;
36
37
    /**
38
     * @var float
39
     */
40
    protected $ctime;
41
42
    /**
43
     * mode & 0777
44
     *
45
     * @var int
46
     */
47
    protected $permissions;
48
49
    /**
50
     * @var int
51
     */
52
    protected $size;
53
54
    /**
55
     * @var int
56
     */
57
    protected $inode;
58
59
    /**
60
     * @var string
61
     */
62
    protected $linkTarget;
63
64
    /**
65
     * Content hashes for file index objects.
66
     *
67
     * @var HashContainer
68
     */
69
    protected $hashes;
70
71
    /**
72
     * @var string
73
     */
74
    protected $blobId;
75
76
    public function __construct(string $relativePath, int $type, float $mtime, ?float $ctime, int $permissions, ?int $size, ?int $inode, ?string $linkTarget, ?string $blobId, ?HashContainer $hashContainer)
77
    {
78
        assert(($type === static::TYPE_FILE) ^ ($size === null));
79
        assert(($type === static::TYPE_FILE) || ($blobId === null));
80
        assert(($type === static::TYPE_FILE) ^ ($hashContainer === null));
81
        assert(($type === static::TYPE_LINK) ^ ($linkTarget === null));
82
        assert(!($permissions & ~0777));
83
84
        $this->relativePath = $relativePath;
85
        $this->type = $type;
86
        $this->mtime = $mtime;
87
        $this->ctime = $ctime;
88
        $this->permissions = $permissions;
89
        $this->size = $size;
90
        $this->inode = $inode;
91
        $this->linkTarget = $linkTarget;
92
        $this->blobId = $blobId;
93
        $this->hashes = $hashContainer;
94
    }
95
96
    public function getRelativePath(): string
97
    {
98
        return $this->relativePath;
99
    }
100
101
    public function getBasename(): string
102
    {
103
        $pos = strrpos($this->relativePath, '/');
104
105
        return ($pos === false) ? $this->relativePath : substr($this->relativePath, $pos + 1);
106
    }
107
108
    public function getType(): int
109
    {
110
        return $this->type;
111
    }
112
113
    public function getTypeName(): string
114
    {
115
        return static::getTypeNameMap()[$this->type];
116
    }
117
118
    public function isDirectory(): bool
119
    {
120
        return $this->type === static::TYPE_DIR;
121
    }
122
123
    public function isFile(): bool
124
    {
125
        return $this->type === static::TYPE_FILE;
126
    }
127
128
    public function isLink(): bool
129
    {
130
        return $this->type === static::TYPE_LINK;
131
    }
132
133
    public function getMtime(): float
134
    {
135
        return $this->mtime;
136
    }
137
138
    public function getCtime(): ?float
139
    {
140
        return $this->ctime;
141
    }
142
143
    public function setCtime(float $ctime): IndexObject
144
    {
145
        $this->ctime = $ctime;
146
147
        return $this;
148
    }
149
150
    public function getPermissions(): int
151
    {
152
        return $this->permissions;
153
    }
154
155
    public function getPermissionsString(): string
156
    {
157
        return decoct($this->permissions);
158
    }
159
160
    public function getSize(): ?int
161
    {
162
        return $this->size;
163
    }
164
165
    public function getInode(): ?int
166
    {
167
        return $this->inode;
168
    }
169
170
    public function getLinkTarget(): ?string
171
    {
172
        return $this->linkTarget;
173
    }
174
175
    public function getHashes(): ?HashContainer
176
    {
177
        return $this->hashes;
178
    }
179
180
    public function getBlobId(): ?string
181
    {
182
        return $this->blobId;
183
    }
184
185
    public function setBlobId(string $blobId): IndexObject
186
    {
187
        assert($this->blobId === null);
188
189
        $this->blobId = $blobId;
190
191
        return $this;
192
    }
193
194
    /**
195
     * Equality check with all attributes.
196
     *
197
     * @param IndexObject $other
198
     * @param int $options
199
     * @return bool
200
     */
201
    public function equals(?IndexObject $other, int $options = 0): bool
202
    {
203
        if ($other === null)
204
        {
205
            return false;
206
        }
207
208
        $equals = true;
209
        $equals &= $this->relativePath === $other->relativePath;
210
        $equals &= $this->type === $other->type;
211
        $equals &= $this->mtime === $other->mtime;
212
        $equals &= ($options & static::CMP_IGNORE_CTIME) || ($this->ctime === $other->ctime);
213
        $equals &= $this->permissions === $other->permissions;
214
        $equals &= $this->size === $other->size;
215
        $equals &= ($options & static::CMP_IGNORE_INODE) || ($this->inode === $other->inode);
216
        $equals &= $this->linkTarget === $other->linkTarget;
217
        $equals &= ($options & static::CMP_IGNORE_BLOBID) || ($this->blobId === $other->blobId);
218
219
        if ($this->hashes && $other->hashes)
220
        {
221
            $equals &= $this->hashes->equals($other->hashes);
222
        }
223
224
        return $equals;
225
    }
226
227
    /**
228
     * @inheritdoc
229
     */
230
    public function offsetExists($offset)
231
    {
232
        return method_exists($this, 'get' . ucfirst($offset));
233
    }
234
235
    /**
236
     * @inheritdoc
237
     */
238
    public function offsetGet($offset)
239
    {
240
        assert(method_exists($this, 'get' . ucfirst($offset)));
241
242
        return call_user_func([$this, 'get' . ucfirst($offset)]);
243
    }
244
245
    /**
246
     * @inheritdoc
247
     */
248
    public function offsetSet($offset, $value)
249
    {
250
        throw new \LogicException();
251
    }
252
253
    /**
254
     * @inheritdoc
255
     */
256
    public function offsetUnset($offset)
257
    {
258
        throw new \LogicException();
259
    }
260
261
    public function __clone()
262
    {
263
        if ($this->hashes !== null)
264
        {
265
            $this->hashes = clone $this->hashes;
266
        }
267
    }
268
269
    public function __toString(): string
270
    {
271
        $parts = [
272
            $this->getTypeName(),
273
            "mtime: " . ($this->mtime === null ? '-' : FilesystemUtility::buildTime($this->mtime)),
274
            "ctime: " . ($this->ctime === null ? '-' : FilesystemUtility::buildTime($this->ctime)),
275
            "permissions: 0{$this->getPermissionsString()}",
276
            "inode: " . $this->inode ?: '-',
277
        ];
278
279
        if ($this->isFile())
280
        {
281
            $blobId = $this->blobId ?: '-';
282
283
            $parts = array_merge($parts, [
284
                "size: {$this->size} B",
285
                "blobId: {$blobId}",
286
            ]);
287
        }
288
        elseif ($this->isLink())
289
        {
290
            $parts = array_merge($parts, [
291
                "target: {$this->linkTarget}",
292
            ]);
293
        }
294
295
        $attributesString = implode(', ', $parts);
296
297
        return "{$this->relativePath} ({$attributesString})";
298
    }
299
300
    public static function getTypeNameMap(): array
301
    {
302
        return [
303
            static::TYPE_DIR => 'DIR',
304
            static::TYPE_FILE => 'FILE',
305
            static::TYPE_LINK => 'LINK',
306
        ];
307
    }
308
}
309