Completed
Branch master (3adcdb)
by Raffael
08:09 queued 04:17
created

Gridfs::deleteFile()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 46
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 46
rs 8.4751
c 0
b 0
f 0
cc 6
eloc 25
nc 7
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\Storage\Adapter;
13
14
use Balloon\Filesystem\Exception;
15
use Balloon\Filesystem\Node\Collection;
16
use Balloon\Filesystem\Node\File;
17
use Balloon\Filesystem\Node\NodeInterface;
18
use MongoDB\BSON\ObjectId;
19
use MongoDB\Database;
20
use MongoDB\GridFS\Bucket;
21
use Psr\Log\LoggerInterface;
22
23
class Gridfs implements AdapterInterface
24
{
25
    /**
26
     * Database.
27
     *
28
     * @var Database
29
     */
30
    protected $db;
31
32
    /**
33
     * GridFS.
34
     *
35
     * @var Bucket
36
     */
37
    protected $gridfs;
38
39
    /**
40
     * Logger.
41
     *
42
     * @var LoggerInterface
43
     */
44
    protected $logger;
45
46
    /**
47
     * GridFS storage.
48
     *
49
     * @param Database
50
     * @param LoggerInterface $logger
51
     */
52
    public function __construct(Database $db, LoggerInterface $logger)
53
    {
54
        $this->db = $db;
55
        $this->gridfs = $db->selectGridFSBucket();
56
        $this->logger = $logger;
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    public function hasNode(NodeInterface $node, array $attributes): bool
63
    {
64
        return null !== $this->getFileById($attributes);
0 ignored issues
show
Documentation introduced by
$attributes is of type array, but the function expects a object<MongoDB\BSON\ObjectId>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
65
    }
66
67
    /**
68
     * {@inheritdoc}
69
     */
70
    public function deleteFile(File $file, array $attributes): bool
71
    {
72
        if (!isset($attributes['_id'])) {
73
            throw new Exception('attributes do not contain a gridfs id');
74
        }
75
76
        $exists = $this->getFileById($attributes['_id']);
77
78
        if (null === $exists) {
79
            $this->logger->debug('gridfs content node ['.$exists['_id'].'] was not found, file reference=['.$file->getId().']', [
80
                'category' => get_class($this),
81
            ]);
82
83
            return false;
84
        }
85
86
        if (!isset($exists['metadata']['references'])) {
87
            $this->gridfs->delete($exists['_id']);
88
89
            return true;
90
        }
91
92
        $refs = $exists['metadata']['references'];
93
        if (($key = array_search($file->getId(), $refs)) !== false) {
94
            unset($refs[$key]);
95
            $refs = array_values($refs);
96
        }
97
98
        if (count($refs) >= 1) {
99
            $this->logger->debug('gridfs content node ['.$exists['_id'].'] still has references left, just remove the reference ['.$file->getId().']', [
100
                'category' => get_class($this),
101
            ]);
102
103
            $this->db->{'fs.files'}->updateOne(['_id' => $exists['_id']], [
104
                '$set' => ['metadata.references' => $refs],
105
            ]);
106
        } else {
107
            $this->logger->debug('gridfs content node ['.$exists['_id'].'] has no references left, delete node completely', [
108
                'category' => get_class($this),
109
            ]);
110
111
            $this->gridfs->delete($exists['_id']);
112
        }
113
114
        return true;
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function getFile(File $file, array $attributes)
121
    {
122
        if (!isset($attributes['_id'])) {
123
            throw new Exception('attributes do not contain a gridfs id');
124
        }
125
126
        return $this->gridfs->openDownloadStream($attributes['_id']);
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132
    public function storeFile(File $file, $contents): array
133
    {
134
        $exists = $this->getFileByHash($file->getHash());
135
136
        if (null === $exists) {
137
            return $this->storeNew($file, $contents);
138
        }
139
140
        $this->logger->info('gridfs content node with hash ['.$file->getHash().'] does already exists,
141
          add new file reference for ['.$file->getId().']', [
142
            'category' => get_class($this),
143
        ]);
144
145
        $action['$addToSet'] = [
0 ignored issues
show
Coding Style Comprehensibility introduced by
$action was never initialized. Although not strictly required by PHP, it is generally a good practice to add $action = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
146
            'metadata.references' => $file->getId(),
147
        ];
148
149
        $this->db->{'fs.files'}->updateOne(['md5' => $file->getHash()], $action);
150
151
        return ['_id' => $exists['_id']];
152
    }
153
154
    /**
155
     * Create collection.
156
     *
157
     * @return array
158
     */
159
    public function createCollection(Collection $collection): array
160
    {
161
        return [];
162
    }
163
164
    /**
165
     * Get stored file.
166
     *
167
     * @param ObjectId $id
168
     *
169
     * @return array
170
     */
171
    protected function getFileById(ObjectId $id): ?array
172
    {
173
        return $this->gridfs->findOne(['_id' => $id]);
174
    }
175
176
    /**
177
     * Get stored file.
178
     *
179
     * @param string $hash
180
     *
181
     * @return array
182
     */
183
    protected function getFileByHash(string $hash): ?array
184
    {
185
        return $this->gridfs->findOne(['md5' => $hash]);
186
    }
187
188
    /**
189
     * Store new file.
190
     *
191
     * @param File     $file
192
     * @param resource $contents
193
     *
194
     * @return array
195
     */
196
    protected function storeNew(File $file, $contents): array
197
    {
198
        set_time_limit((int) ($file->getSize() / 15339168));
199
        $id = new ObjectId();
200
201
        //somehow mongo-connector does not catch metadata when set during uploadFromStream()
202
        $stream = $this->gridfs->uploadFromStream($id, $contents, ['_id' => $id, 'metadata' => [
0 ignored issues
show
Unused Code introduced by
$stream 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...
203
            'references' => [
204
                $file->getId(),
205
            ],
206
        ]]);
207
208
        $this->logger->info('added new gridfs content node ['.$id.'] for file ['.$file->getId().']', [
209
            'category' => get_class($this),
210
        ]);
211
212
        return ['_id' => $id];
213
    }
214
}
215