Passed
Pull Request — final (#553)
by Georges
02:18
created

Driver::driverWrite()   C

Complexity

Conditions 8
Paths 43

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 34
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 20
nc 43
nop 1
1
<?php
2
/**
3
 *
4
 * This file is part of phpFastCache.
5
 *
6
 * @license MIT License (MIT)
7
 *
8
 * For full copyright and license information, please see the docs/CREDITS.txt file.
9
 *
10
 * @author Khoa Bui (khoaofgod)  <[email protected]> http://www.phpfastcache.com
11
 * @author Georges.L (Geolim4)  <[email protected]>
12
 * @author Fabio Covolo Mazzo (fabiocmazzo) <[email protected]>
13
 *
14
 */
15
16
namespace phpFastCache\Drivers\Mongodb;
17
18
use LogicException;
19
use MongoDB\BSON\Binary;
20
use MongoDB\BSON\UTCDateTime;
21
use MongoDB\Collection;
22
use MongoDB\DeleteResult;
23
use MongoDB\Driver\Command;
24
use MongoDB\Driver\Exception\Exception as MongoDBException;
25
use MongoDB\Driver\Manager as MongodbManager;
26
use phpFastCache\Core\Pool\DriverBaseTrait;
27
use phpFastCache\Core\Pool\ExtendedCacheItemPoolInterface;
28
use phpFastCache\Entities\DriverStatistic;
29
use phpFastCache\Exceptions\phpFastCacheDriverCheckException;
30
use phpFastCache\Exceptions\phpFastCacheDriverException;
31
use phpFastCache\Exceptions\phpFastCacheInvalidArgumentException;
32
use Psr\Cache\CacheItemInterface;
33
34
/**
35
 * Class Driver
36
 * @package phpFastCache\Drivers
37
 * @property MongodbManager $instance Instance of driver service
38
 */
39
class Driver implements ExtendedCacheItemPoolInterface
40
{
41
    use DriverBaseTrait;
42
43
    /**
44
     * @var Collection
45
     */
46
    public $collection;
47
48
    /**
49
     * Driver constructor.
50
     * @param array $config
51
     * @throws phpFastCacheDriverCheckException
52
     */
53
    public function __construct(array $config = [])
54
    {
55
        $this->setup($config);
56
57
        if (!$this->driverCheck()) {
58
            throw new phpFastCacheDriverCheckException(sprintf(self::DRIVER_CHECK_FAILURE, $this->getDriverName()));
59
        } else {
60
            $this->driverConnect();
61
        }
62
    }
63
64
    /**
65
     * @return bool
66
     */
67
    public function driverCheck()
68
    {
69
        if (!class_exists('MongoDB\Driver\Manager') && class_exists('MongoClient')) {
70
            trigger_error('This driver is used to support the pecl MongoDb extension with mongo-php-library.
71
            For MongoDb with Mongo PECL support use Mongo Driver.', E_USER_ERROR);
72
        }
73
74
        return class_exists('MongoDB\Collection');
75
    }
76
77
    /**
78
     * @param \Psr\Cache\CacheItemInterface $item
79
     * @return mixed
80
     * @throws phpFastCacheInvalidArgumentException
81
     * @throws phpFastCacheDriverException
82
     */
83
    protected function driverWrite(CacheItemInterface $item)
84
    {
85
        /**
86
         * Check for Cross-Driver type confusion
87
         */
88
        if ($item instanceof Item) {
89
            try {
90
                $set = [
91
                  self::DRIVER_DATA_WRAPPER_INDEX => new Binary($this->encode($item->get()), Binary::TYPE_GENERIC),
92
                  self::DRIVER_TAGS_WRAPPER_INDEX => new Binary($this->encode($item->getTags()), Binary::TYPE_GENERIC),
93
                  self::DRIVER_EDATE_WRAPPER_INDEX => ($item->getTtl() > 0 ? new UTCDateTime((time() + $item->getTtl()) * 1000) : new UTCDateTime(time() * 1000)),
94
                ];
95
96
                if(!empty($this->config[ 'itemDetailedDate' ])){
97
                    $set += [
98
                      self::DRIVER_MDATE_WRAPPER_INDEX => ($item->getModificationDate() ? new UTCDateTime(($item->getModificationDate()->getTimestamp()) * 1000) : new UTCDateTime(time() * 1000)),
99
                      self::DRIVER_CDATE_WRAPPER_INDEX => ($item->getCreationDate() ? new UTCDateTime(($item->getCreationDate()->getTimestamp()) * 1000) : new UTCDateTime(time() * 1000)),
100
                    ];
101
                }
102
103
                $result = (array)$this->getCollection()->updateOne(
104
                  ['_id' => $item->getEncodedKey()],
105
                  ['$set' => $set],
106
                  ['upsert' => true, 'multiple' => false]
107
                );
108
            } catch (MongoDBException $e) {
0 ignored issues
show
Bug introduced by
The class MongoDB\Driver\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
109
                throw new phpFastCacheDriverException('Got an exception while trying to write data to MongoDB server', null, $e);
110
            }
111
112
            return isset($result[ 'ok' ]) ? $result[ 'ok' ] == 1 : true;
113
        } else {
114
            throw new phpFastCacheInvalidArgumentException('Cross-Driver type confusion detected');
115
        }
116
    }
117
118
    /**
119
     * @param \Psr\Cache\CacheItemInterface $item
120
     * @return null|array
121
     */
122
    protected function driverRead(CacheItemInterface $item)
123
    {
124
        $document = $this->getCollection()->findOne(['_id' => $item->getEncodedKey()]);
125
126
        if ($document) {
127
            $return = [
128
              self::DRIVER_DATA_WRAPPER_INDEX => $this->decode($document[ self::DRIVER_DATA_WRAPPER_INDEX ]->getData()),
129
              self::DRIVER_TAGS_WRAPPER_INDEX => $this->decode($document[ self::DRIVER_TAGS_WRAPPER_INDEX ]->getData()),
130
              self::DRIVER_EDATE_WRAPPER_INDEX => (new \DateTime())->setTimestamp($document[ self::DRIVER_EDATE_WRAPPER_INDEX ]->toDateTime()->getTimestamp()),
131
            ];
132
133
            if(!empty($this->config[ 'itemDetailedDate' ])){
134
                $return += [
135
                  self::DRIVER_MDATE_WRAPPER_INDEX => (new \DateTime())->setTimestamp($document[ self::DRIVER_MDATE_WRAPPER_INDEX ]->toDateTime()->getTimestamp()),
136
                  self::DRIVER_CDATE_WRAPPER_INDEX => (new \DateTime())->setTimestamp($document[ self::DRIVER_CDATE_WRAPPER_INDEX ]->toDateTime()->getTimestamp()),
137
                ];
138
            }
139
140
            return $return;
141
        } else {
142
            return null;
143
        }
144
    }
145
146
    /**
147
     * @param \Psr\Cache\CacheItemInterface $item
148
     * @return bool
149
     * @throws phpFastCacheInvalidArgumentException
150
     */
151
    protected function driverDelete(CacheItemInterface $item)
152
    {
153
        /**
154
         * Check for Cross-Driver type confusion
155
         */
156
        if ($item instanceof Item) {
157
            /**
158
             * @var DeleteResult $deletionResult
159
             */
160
            $deletionResult = $this->getCollection()->deleteOne(['_id' => $item->getEncodedKey()]);
161
162
            return $deletionResult->isAcknowledged();
163
        } else {
164
            throw new phpFastCacheInvalidArgumentException('Cross-Driver type confusion detected');
165
        }
166
    }
167
168
    /**
169
     * @return bool
170
     */
171
    protected function driverClear()
172
    {
173
        /**
174
         * @var \MongoDB\Model\BSONDocument $result
175
         */
176
        $result = $this->getCollection()->drop()->getArrayCopy();
177
        $this->collection = new Collection($this->instance, 'phpFastCache', 'Cache');
178
179
        /**
180
         * This will rebuild automatically the Collection indexes
181
         */
182
        $this->save($this->getItem('__PFC_CACHE_CLEARED__')->set(true));
183
184
        return !empty($result[ 'ok' ]);
185
    }
186
187
    /**
188
     * @return bool
189
     * @throws MongodbException
190
     * @throws LogicException
191
     */
192
    protected function driverConnect()
193
    {
194
        if ($this->instance instanceof \MongoDB\Driver\Manager) {
195
            throw new LogicException('Already connected to Mongodb server');
196
        } else {
197
            $host = isset($this->config[ 'host' ]) ? $this->config[ 'host' ] : '127.0.0.1';
198
            $port = isset($this->config[ 'port' ]) ? $this->config[ 'port' ] : '27017';
199
            $timeout = isset($this->config[ 'timeout' ]) ? $this->config[ 'timeout' ] : 3;
200
            $password = isset($this->config[ 'password' ]) ? $this->config[ 'password' ] : '';
201
            $username = isset($this->config[ 'username' ]) ? $this->config[ 'username' ] : '';
202
            $collectionName = isset($this->config[ 'collectionName' ]) ? $this->config[ 'collectionName' ] : 'Cache';
203
            $databaseName = isset($this->config[ 'databaseName' ]) ? $this->config[ 'databaseName' ] : 'phpFastCache';
204
205
206
            /**
207
             * @todo make an url builder
208
             */
209
            $this->instance = $this->instance ?: (new MongodbManager('mongodb://' .
210
              ($username ?: '') .
211
              ($password ? ":{$password}" : '') .
212
              ($username ? '@' : '') . "{$host}" .
213
              ($port != '27017' ? ":{$port}" : ''), ['connectTimeoutMS' => $timeout * 1000]));
214
            $this->collection = $this->collection ?: new Collection($this->instance, $databaseName, $collectionName);
215
216
            return true;
217
        }
218
    }
219
220
221
    /**
222
     * @return Collection
223
     */
224
    protected function getCollection()
225
    {
226
        return $this->collection;
227
    }
228
229
    /********************
230
     *
231
     * PSR-6 Extended Methods
232
     *
233
     *******************/
234
235
    /**
236
     * @return DriverStatistic
237
     */
238
    public function getStats()
239
    {
240
        $serverStats = $this->instance->executeCommand('phpFastCache', new Command([
241
          'serverStatus' => 1,
242
          'recordStats' => 0,
243
          'repl' => 0,
244
          'metrics' => 0,
245
        ]))->toArray()[ 0 ];
246
247
        $collectionStats = $this->instance->executeCommand('phpFastCache', new Command([
248
          'collStats' => (isset($this->config[ 'collectionName' ]) ? $this->config[ 'collectionName' ] : 'Cache'),
249
          'verbose' => true,
250
        ]))->toArray()[ 0 ];
251
252
        $array_filter_recursive = function ($array, callable $callback = null) use (&$array_filter_recursive) {
253
            $array = $callback($array);
254
255
            if (is_object($array) || is_array($array)) {
256
                foreach ($array as &$value) {
257
                    $value = call_user_func($array_filter_recursive, $value, $callback);
258
                }
259
            }
260
261
            return $array;
262
        };
263
264
        $callback = function ($item) {
265
            /**
266
             * Remove unserializable properties
267
             */
268
            if ($item instanceof \MongoDB\BSON\UTCDateTime) {
0 ignored issues
show
Bug introduced by
The class MongoDB\BSON\UTCDateTime does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
269
                return (string)$item;
270
            }
271
            return $item;
272
        };
273
274
        $serverStats = $array_filter_recursive($serverStats, $callback);
275
        $collectionStats = $array_filter_recursive($collectionStats, $callback);
276
277
        $stats = (new DriverStatistic())
278
          ->setInfo('MongoDB version ' . $serverStats->version . ', Uptime (in days): ' . round($serverStats->uptime / 86400,
279
              1) . "\n For more information see RawData.")
280
          ->setSize($collectionStats->size)
281
          ->setData(implode(', ', array_keys($this->itemInstances)))
282
          ->setRawData([
283
            'serverStatus' => $serverStats,
284
            'collStats' => $collectionStats,
285
          ]);
286
287
        return $stats;
288
    }
289
}
290