Completed
Pull Request — master (#220)
by
unknown
03:44
created

MongoGridFS::storeBytes()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 4
Ratio 25 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 4
nop 3
dl 4
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 */
15
16
use Alcaeus\MongoDbAdapter\ExceptionConverter;
17
use Alcaeus\MongoDbAdapter\TypeConverter;
18
19
if (class_exists('MongoGridFS', false)) {
20
    return;
21
}
22
23
class MongoGridFS extends MongoCollection
24
{
25
    const ASCENDING = 1;
26
    const DESCENDING = -1;
27
28
    /**
29
     * @link http://php.net/manual/en/class.mongogridfs.php#mongogridfs.props.chunks
30
     * @var $chunks MongoCollection
31
     */
32
    public $chunks;
33
34
    /**
35
     * @link http://php.net/manual/en/class.mongogridfs.php#mongogridfs.props.filesname
36
     * @var $filesName string
37
     */
38
    protected $filesName;
39
40
    /**
41
     * @link http://php.net/manual/en/class.mongogridfs.php#mongogridfs.props.chunksname
42
     * @var $chunksName string
43
     */
44
    protected $chunksName;
45
46
    /**
47
     * @var MongoDB
48
     */
49
    private $database;
50
51
    private $prefix;
52
53
    private $defaultChunkSize = 261120;
0 ignored issues
show
Unused Code introduced by
The property $defaultChunkSize is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
54
55
    /**
56
     * @var \MongoDB\GridFS\Bucket
57
     */
58
    private $bucket;
59
60
    /**
61
     * Files as stored across two collections, the first containing file meta
62
     * information, the second containing chunks of the actual file. By default,
63
     * fs.files and fs.chunks are the collection names used.
64
     *
65
     * @link http://php.net/manual/en/mongogridfs.construct.php
66
     * @param MongoDB $db Database
67
     * @param string $prefix [optional] <p>Optional collection name prefix.</p>
68
     * @param mixed $chunks  [optional]
69
     * @throws \Exception
70
     */
71
    public function __construct(MongoDB $db, $prefix = "fs", $chunks = null)
72
    {
73
        if ($chunks) {
74
            trigger_error("The 'chunks' argument is deprecated and ignored", E_USER_DEPRECATED);
75
        }
76
        if (empty($prefix)) {
77
            throw new \Exception('MongoGridFS::__construct(): invalid prefix');
78
        }
79
80
        $this->database = $db;
81
        $this->bucket = $db->getDb()->selectGridFSBucket(['bucketName' => $prefix]);
82
        $this->prefix = (string) $prefix;
83
        $this->filesName = $this->bucket->getFilesCollection()->getCollectionName();
84
        $this->chunksName = $this->bucket->getChunksCollection()->getCollectionName();
85
86
        $this->chunks = $db->selectCollection($this->chunksName);
87
88
        parent::__construct($db, $this->filesName);
89
    }
90
91
    /**
92
     * Delete a file from the database
93
     *
94
     * @link http://php.net/manual/en/mongogridfs.delete.php
95
     * @param mixed $id _id of the file to remove
96
     * @return boolean Returns true if the remove was successfully sent to the database.
97
     */
98
    public function delete($id)
99
    {
100
        try {
101
            $this->bucket->delete(TypeConverter::fromLegacy($id));
102
        } catch (\MongoDB\Driver\Exception\Exception $e) {
103
            throw ExceptionConverter::toLegacy($e);
104
        }
105
106
        return true;
107
    }
108
109
    /**
110
     * Drops the files and chunks collections
111
     * @link http://php.net/manual/en/mongogridfs.drop.php
112
     * @return array The database response
113
     */
114
    public function drop()
115
    {
116
        $this->bucket->drop();
117
118
        return [];
119
    }
120
121
    /**
122
     * @link http://php.net/manual/en/mongogridfs.find.php
123
     * @param array $query The query
124
     * @param array $fields Fields to return
125
     * @param array $options Options for the find command
0 ignored issues
show
Bug introduced by
There is no parameter named $options. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
126
     * @return MongoGridFSCursor A MongoGridFSCursor
127
     */
128 View Code Duplication
    public function find(array $query = [], array $fields = [])
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...
129
    {
130
        $cursor = new MongoGridFSCursor($this, $this->db->getConnection(), (string) $this, $query, $fields);
131
        $cursor->setReadPreference($this->getReadPreference());
0 ignored issues
show
Documentation introduced by
$this->getReadPreference() is of type array, but the function expects a string.

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...
132
133
        return $cursor;
134
    }
135
136
    /**
137
     * Returns a single file matching the criteria
138
     *
139
     * @link http://www.php.net/manual/en/mongogridfs.findone.php
140
     * @param mixed $query The fields for which to search or a filename to search for.
141
     * @param array $fields Fields of the results to return.
142
     * @param array $options Options for the find command
143
     * @return MongoGridFSFile|null
144
     */
145
    public function findOne($query = [], array $fields = [], array $options = [])
146
    {
147
        if (! is_array($query)) {
148
            $query = ['filename' => (string) $query];
149
        }
150
151
        $items = iterator_to_array($this->find($query, $fields)->limit(1));
152
        return count($items) ? current($items) : null;
153
    }
154
155
    /**
156
     * Retrieve a file from the database
157
     *
158
     * @link http://www.php.net/manual/en/mongogridfs.get.php
159
     * @param mixed $id _id of the file to find.
160
     * @return MongoGridFSFile|null
161
     */
162
    public function get($id)
163
    {
164
        return $this->findOne(['_id' => $id]);
165
    }
166
167
    /**
168
     * Stores a file in the database
169
     *
170
     * @link http://php.net/manual/en/mongogridfs.put.php
171
     * @param string $filename The name of the file
172
     * @param array $extra Other metadata to add to the file saved
173
     * @param array $options An array of options for the insert operations executed against the chunks and files collections.
174
     * @return mixed Returns the _id of the saved object
175
     */
176
    public function put($filename, array $extra = [], array $options = [])
177
    {
178
        return $this->storeFile($filename, $extra, $options);
179
    }
180
181
    /**
182
     * Removes files from the collections
183
     *
184
     * @link http://www.php.net/manual/en/mongogridfs.remove.php
185
     * @param array $criteria Description of records to remove.
186
     * @param array $options Options for remove.
187
     * @throws MongoCursorException
188
     * @return boolean
189
     */
190
    public function remove(array $criteria = [], array $options = [])
191
    {
192
        $matchingFiles = parent::find($criteria, ['_id' => 1]);
193
        $ids = [];
194
        foreach ($matchingFiles as $file) {
195
            $ids[] = $file['_id'];
196
        }
197
        $this->chunks->remove(['files_id' => ['$in' => $ids]], ['justOne' => false] + $options);
198
        return parent::remove(['_id' => ['$in' => $ids]], ['justOne' => false] + $options);
199
    }
200
201
    /**
202
     * Chunkifies and stores bytes in the database
203
     * @link http://php.net/manual/en/mongogridfs.storebytes.php
204
     * @param string $bytes A string of bytes to store
205
     * @param array $extra Other metadata to add to the file saved
206
     * @param array $options Options for the store. "safe": Check that this store succeeded
207
     * @return mixed The _id of the object saved
208
     */
209
    public function storeBytes($bytes, array $extra = [], array $options = [])
0 ignored issues
show
Unused Code introduced by
The parameter $options 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
        $filename = isset($extra['filename']) ? $extra['filename'] : 'random' . rand();
212
        $stream = $this->bucket->openUploadStream($filename);
213
        $id = $this->bucket->getFileIdForStream($stream);
214
215
        fwrite($stream, $bytes);
216
        fclose($stream);
217
218 View Code Duplication
        if (count($extra)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
219
            $collection = $this->bucket->getFilesCollection();
220
            $collection->updateOne(['_id' => $id], ['$set' => $extra]);
221
        }
222
223
        return TypeConverter::toLegacy($id);
224
    }
225
226
    /**
227
     * Stores a file in the database
228
     *
229
     * @link http://php.net/manual/en/mongogridfs.storefile.php
230
     * @param string $filename The name of the file
231
     * @param array $extra Other metadata to add to the file saved
232
     * @param array $options Options for the store. "safe": Check that this store succeeded
233
     * @return mixed Returns the _id of the saved object
234
     * @throws MongoGridFSException
235
     * @throws Exception
236
     */
237
    public function storeFile($filename, array $extra = [], array $options = [])
0 ignored issues
show
Unused Code introduced by
The parameter $options 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...
238
    {
239
        $record = $extra;
0 ignored issues
show
Unused Code introduced by
$record 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...
240
        if (is_string($filename)) {
241
            $handle = fopen($filename, 'rb');
242
            if (! $handle) {
243
                throw new MongoGridFSException('could not open file: ' . $filename);
244
            }
245
        } elseif (! is_resource($filename)) {
246
            throw new \Exception('first argument must be a string or stream resource');
247
        } else {
248
            $handle = $filename;
249
            $metadata = stream_get_meta_data($handle);
250
            $filename =  $metadata['uri'];
251
        }
252
        $id = $this->bucket->uploadFromStream($filename, $handle);
253 View Code Duplication
        if (count($extra)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
254
            $collection = $this->bucket->getFilesCollection();
255
            $collection->updateOne(['_id' => $id], ['$set' => $extra]);
256
        }
257
258
        return TypeConverter::toLegacy($id);
259
    }
260
261
    /**
262
     * Saves an uploaded file directly from a POST to the database
263
     *
264
     * @link http://www.php.net/manual/en/mongogridfs.storeupload.php
265
     * @param string $name The name attribute of the uploaded file, from <input type="file" name="something"/>.
266
     * @param array $metadata An array of extra fields for the uploaded file.
267
     * @return mixed Returns the _id of the uploaded file.
268
     * @throws MongoGridFSException
269
     */
270
    public function storeUpload($name, array $metadata = [])
0 ignored issues
show
Coding Style introduced by
storeUpload uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
271
    {
272
        if (! isset($_FILES[$name]) || $_FILES[$name]['error'] !== UPLOAD_ERR_OK) {
273
            throw new MongoGridFSException("Could not find uploaded file $name");
274
        }
275
        if (! isset($_FILES[$name]['tmp_name'])) {
276
            throw new MongoGridFSException("Couldn't find tmp_name in the \$_FILES array. Are you sure the upload worked?");
277
        }
278
279
        $uploadedFile = $_FILES[$name];
280
        $uploadedFile['tmp_name'] = (array) $uploadedFile['tmp_name'];
281
        $uploadedFile['name'] = (array) $uploadedFile['name'];
282
283
        if (count($uploadedFile['tmp_name']) > 1) {
284
            foreach ($uploadedFile['tmp_name'] as $key => $file) {
285
                $metadata['filename'] = $uploadedFile['name'][$key];
286
                $this->storeFile($file, $metadata);
287
            }
288
289
            return null;
290
        } else {
291
            $metadata += ['filename' => array_pop($uploadedFile['name'])];
292
            return $this->storeFile(array_pop($uploadedFile['tmp_name']), $metadata);
293
        }
294
    }
295
296
    /**
297
     * @internal
298
     * @return \MongoDB\GridFS\Bucket
299
     */
300
    public function getBucket()
301
    {
302
        return $this->bucket;
303
    }
304
305
    /**
306
     * @return array
307
     */
308
    public function __sleep()
309
    {
310
        return ['chunks', 'chunksName', 'database', 'defaultChunkSize', 'filesName', 'prefix'] + parent::__sleep();
311
    }
312
}
313