Completed
Push — developer ( 0e4843...531909 )
by Никита
34:20
created

SmallFilesQueueTransport   D

Complexity

Total Complexity 84

Size/Duplication

Total Lines 529
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 83.52%

Importance

Changes 0
Metric Value
wmc 84
lcom 1
cbo 3
dl 0
loc 529
ccs 218
cts 261
cp 0.8352
rs 4.8717
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A set_exclusive_mode() 0 1 1
B __construct() 0 19 5
A get_queue_name() 0 3 1
B save() 0 32 4
A consume_next_message() 0 17 2
A clear_consumed_keys() 0 5 1
A __clone() 0 6 2
C consume_next_message_without_inotify() 0 17 8
B consume_next_message_without_inotify_folder() 0 17 7
B copy_key_to_file_from_messages() 0 9 5
A get_filenames_from_messages() 0 20 4
D delete_messages() 0 109 18
C update_message() 0 67 12
A is_support_sorted_events() 0 3 1
A is_equal_to() 0 11 4
B consume_next_message_from_file() 0 57 9

How to fix   Complexity   

Complex Class

Complex classes like SmallFilesQueueTransport 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 SmallFilesQueueTransport, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
    namespace NokitaKaze\Queue;
4
5
    use NokitaKaze\Mutex\FileMutex;
6
7
    class SmallFilesQueueTransport extends AbstractQueueTransport {
8
        const SINGLE_FILE_DB_VERSION = 1;
9
10
        protected $_message_folder;
11
        protected $_queue_name;
12
        protected $_message_folder_subfolder_count = Queue::DefaultMessageFolderSubfolderCount;
13
        protected $_key_to_file = [];
14
        protected $_is_inotify_enabled;
15
        protected $_chunk_file_postfix = '';
16
17
        /**
18
         * @var iMessage[]
19
         */
20
        protected $_last_consumed_messages = [];
21
        /**
22
         * @var integer[] В keys список файлов, которые были прочитаны
23
         */
24
        protected $_consumed_filenames = [];
25
26
        /**
27
         * @param SmallFilesQueueConstructionSettings|object $settings
28
         *
29
         * @throws QueueException
30
         */
31 68
        function __construct($settings) {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
32 68
            if (!isset($settings->message_folder)) {
33 4
                throw new QueueException('message_folder has not been set');
34
            }
35 64
            if (!isset($settings->name)) {
36 4
                throw new QueueException('name has not been set');
37
            }
38 60
            $this->_message_folder = $settings->message_folder;
39 60
            $this->_queue_name = $settings->name;
40 60
            if (isset($settings->message_folder_subfolder_count)) {
41
                $this->_message_folder_subfolder_count = $settings->message_folder_subfolder_count;
42
            }
43 60
            if (isset($settings->is_inotify_enabled)) {
44
                $this->_is_inotify_enabled = $settings->is_inotify_enabled;
45
            } else {
46 60
                $this->_is_inotify_enabled = function_exists('inotify_init');
47
            }
48 60
            $this->_chunk_file_postfix = '_'.static::generate_rnd_postfix();
49 60
        }
50
51
        /**
52
         * @param boolean $mode
53
         *
54
         * @hint Ничего не делаем, у этого транспорта нет эксклюзивного режима
55
         * @codeCoverageIgnore
56
         */
57
        function set_exclusive_mode($mode) { }
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
58
59
        /**
60
         * @return string
61
         */
62 692
        function get_queue_name() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
63 692
            return $this->_queue_name;
64
        }
65
66 620
        function save() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
67 620
            $this->set_same_time_flag(1);
68 620
            if (empty($this->_pushed_for_save)) {
69 16
                return;
70
            }
71
72
            /**
73
             * @var SmallFilesQueueSingleFile $data
74
             */
75 620
            $data = (object) [];
76 620
            $data->queue = $this->_pushed_for_save;
0 ignored issues
show
Bug introduced by
Accessing queue on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
77 620
            $data->queue_name = $this->_queue_name;
0 ignored issues
show
Bug introduced by
Accessing queue_name on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
78 620
            $data->time_create = microtime(true);
0 ignored issues
show
Bug introduced by
Accessing time_create on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
79 620
            $data->time_last_update = microtime(true);
0 ignored issues
show
Bug introduced by
Accessing time_last_update on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
80 620
            $data->version = self::SINGLE_FILE_DB_VERSION;
0 ignored issues
show
Bug introduced by
Accessing version on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
81 620
            $num = mt_rand(0, $this->_message_folder_subfolder_count - 1);
82 620
            $folder = $this->_message_folder.'/'.$num;
83 620
            FileMutex::create_folders_in_path($folder);
84 620
            $filename = sprintf('%s/smartqueue_%s%s.chunk.dat',
85 620
                $folder, number_format(microtime(true), 4, '.', ''), $this->_chunk_file_postfix);
86
87 620
            $u = file_put_contents($filename, serialize($data), LOCK_EX);
88 620
            if ($u === false) {
89
                // @codeCoverageIgnoreStart
90
                throw new QueueException('Can not save queue to a file: '.FileMutex::get_last_php_error_as_string());
91
                // @codeCoverageIgnoreEnd
92
            }
93 620
            foreach ($this->_pushed_for_save as $message) {
94 620
                $this->_key_to_file[static::get_real_key_for_message($message)] = $filename;
95 155
            }
96 620
            $this->_pushed_for_save = [];
97 620
        }
98
99
        /**
100
         * @param double|integer $wait_time
101
         *
102
         * @return iMessage|object|null
103
         * @throws QueueException
104
         */
105 696
        function consume_next_message($wait_time = -1) {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
106 696
            $this->set_same_time_flag(2);
107 696
            if (!empty($this->_last_consumed_messages)) {
108 560
                return array_shift($this->_last_consumed_messages);
109
            }
110
111 696
            return $this->consume_next_message_without_inotify($wait_time);
112
            /*
113
            if ($this->_is_inotify_enabled and false) {// @todo добавить Inotify
114
                // @codeCoverageIgnoreStart
115
                return $this->consume_next_message_with_inotify($wait_time);
116
                // @codeCoverageIgnoreEnd
117
            } else {
118
                return $this->consume_next_message_without_inotify($wait_time);
119
            }
120
            */
121
        }
122
123 8
        function clear_consumed_keys() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
124 8
            parent::clear_consumed_keys();
125 8
            $this->_last_consumed_messages = [];
126 8
            $this->_consumed_filenames = [];
127 8
        }
128
129 736
        function __clone() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
130 736
            parent::__clone();
131 736
            foreach ($this->_last_consumed_messages as &$message) {
132
                $message = clone $message;
133 184
            }
134 736
        }
135
136
        /**
137
         * @param double|integer $wait_time
138
         *
139
         * @return iMessage|object|null
140
         */
141 696
        protected function consume_next_message_without_inotify($wait_time = -1) {
142 696
            $start = microtime(true);
143
            do {
144 696
                for ($i = 0; $i < $this->_message_folder_subfolder_count; $i++) {
145 696
                    $folder = $this->_message_folder.'/'.$i;
146 696
                    if (!file_exists($folder) or !is_readable($folder) or !is_dir($folder)) {
147 620
                        continue;
148
                    }
149 680
                    $event = $this->consume_next_message_without_inotify_folder($folder);
150 680
                    if (!is_null($event)) {
151 680
                        return $event;
152
                    }
153 165
                }
154 668
            } while (($wait_time == -1) or ($start + $wait_time >= microtime(true)));
155
156 668
            return null;
157
        }
158
159
        /**
160
         * @param string $folder
161
         *
162
         * @return iMessage|object|null
163
         */
164 680
        protected function consume_next_message_without_inotify_folder($folder) {
165 680
            foreach (scandir($folder) as $f) {
166 680
                if (in_array($f, ['.', '..']) or !preg_match('|smartqueue_[0-9.]+(_[a-z0-9]+)?\\.chunk\\.dat$|', $f)) {
167 680
                    continue;
168
                }
169 680
                $filename = $folder.'/'.$f;
170 680
                if (is_dir($filename) or !is_readable($filename)) {
171
                    continue;
172
                }
173 680
                $event = $this->consume_next_message_from_file($filename);
174 680
                if (!is_null($event)) {
175 680
                    return $event;
176
                }
177 165
            }
178
179 660
            return null;
180
        }
181
182
183
        /**
184
         * Забираем новые event'ы из файла. Файл должен быть уже существующим, читабельным
185
         *
186
         * Проверка на присутствие в индексе осуществляется в этом файле
187
         *
188
         * @param string $filename
189
         *
190
         * @return iMessage|object|null
191
         */
192 680
        protected function consume_next_message_from_file($filename) {
193 680
            if (isset($this->_consumed_filenames[$filename])) {
194 660
                return null;
195
            }
196
197 680
            $fi = fopen($filename, 'r');
198 680
            $locked = flock($fi, LOCK_EX | LOCK_NB);
199 680
            if (!$locked) {
200 4
                fclose($fi);
201
202 4
                return null;
203
            }
204
205 680
            $buf = file_get_contents($filename);
206
            /**
207
             * @var SmallFilesQueueSingleFile $file_data
208
             */
209 680
            $file_data = @unserialize($buf);
210 680
            if (!is_object($file_data)) {
211
                // File does not contain Single Queue object
212 3
                flock($fi, LOCK_UN);
213 3
                fclose($fi);
214
215 3
                return null;
216
            }
217 680
            if ($file_data->queue_name != $this->get_queue_name()) {
218 8
                flock($fi, LOCK_UN);
219 8
                fclose($fi);
220
221 8
                return null;
222
            }
223 680
            if ($file_data->version != self::SINGLE_FILE_DB_VERSION) {
224
                flock($fi, LOCK_UN);
225
                fclose($fi);
226
227
                return null;
228
            }
229
230 680
            $this->_last_consumed_messages = [];
231 680
            foreach ($file_data->queue as $message) {
232 680
                $key = self::get_real_key_for_message($message);
233 680
                if (isset($this->_consumed_keys[$key])) {
234 8
                    continue;
235
                }
236
237 680
                $message->time_consumed = microtime(true);
238 680
                $message->queue = $this;
239 680
                $this->_key_to_file[$key] = $filename;
240 680
                $this->_last_consumed_messages[] = $message;
241 680
                $this->_consumed_keys[$key] = 1;
242 170
            }
243 680
            flock($fi, LOCK_UN);
244 680
            fclose($fi);
245 680
            $this->_consumed_filenames[$filename] = 1;
246
247 680
            return !empty($this->_last_consumed_messages) ? array_shift($this->_last_consumed_messages) : null;
248
        }
249
250
        /**
251
         * @param iMessage[]|object[] $messages
252
         */
253 312
        protected function copy_key_to_file_from_messages(array $messages) {
254 312
            foreach ($messages as $message) {
255 312
                if (isset($message->queue) and (get_class($message->queue) == self::class)) {
256 312
                    foreach ($message->queue->_key_to_file as $key => $filename) {
257 312
                        $this->_key_to_file[$key] = $filename;
258 78
                    }
259 78
                }
260 78
            }
261 312
        }
262
263
        /**
264
         * @param iMessage[]|object[] $messages
265
         *
266
         * @return array[]
267
         */
268 312
        protected function get_filenames_from_messages(array $messages) {
269 312
            $this->copy_key_to_file_from_messages($messages);
270 312
            $filenames = [];
271 312
            $filenames_contains_keys = [];
272 312
            foreach ($messages as $message) {
273 312
                $key = self::get_real_key_for_message($message);
274 312
                if (!isset($this->_key_to_file[$key])) {
275 216
                    continue;
276
                }
277 312
                $filename = $this->_key_to_file[$key];
278 312
                $filenames[] = $filename;
279 312
                if (!isset($filenames_contains_keys[$filename])) {
280 312
                    $filenames_contains_keys[$filename] = [];
281 78
                }
282
283 312
                $filenames_contains_keys[$filename][] = $key;
284 78
            }
285
286 312
            return [$filenames, $filenames_contains_keys];
287
        }
288
289
        /**
290
         * Удалить сообщения и сразу же записать это в БД
291
         *
292
         * @param iMessage[]|object[] $messages
293
         *
294
         * @return string[]|integer[]
295
         * @throws QueueException
296
         */
297 312
        function delete_messages(array $messages) {
298
            /**
299
             * @var string[][] $filenames_contains_keys
300
             * @var string[]   $filenames
301
             */
302 312
            list($filenames, $filenames_contains_keys) = $this->get_filenames_from_messages($messages);
303 312
            $filenames_contains_keys_all = [];
304 312
            foreach ($this->_key_to_file as $key => $filename) {
305 312
                if (isset($filenames_contains_keys_all[$filename])) {
306 220
                    $filenames_contains_keys_all[$filename][] = $key;
307 55
                } else {
308 312
                    $filenames_contains_keys_all[$filename] = [$key];
309
                }
310 78
            }
311 312
            unset($key, $filename);
312
313 312
            $deleted_keys = [];
314 312
            foreach ($filenames as $filename) {
315 312
                if (!file_exists($filename)) {
316
                    // @todo Надо подумать правильный ли это подход
317
                    // Тут будут все ключи, а не только те, которые надо было удалить
318 211
                    $deleted_keys = array_merge($deleted_keys, $filenames_contains_keys[$filename]);
319 211
                    continue;
320
                }
321 312
                if (!is_writable($filename)) {
322
                    throw new QueueException('Can not delete messages from read only files');
323
                }
324 312
                if (count($filenames_contains_keys[$filename]) == count($filenames_contains_keys_all[$filename])) {
325
                    // Нужно удалить все записи в файле, значит можно просто удалить файл целиком
326 247
                    if (!unlink($filename)) {
327
                        // @codeCoverageIgnoreStart
328
                        throw new QueueException('Can not delete file '.$filename.': '.
329
                                                 FileMutex::get_last_php_error_as_string());
330
                        // @codeCoverageIgnoreEnd
331
                    }
332 247
                    $deleted_keys = array_merge($deleted_keys, $filenames_contains_keys[$filename]);
333 247
                    continue;
334
                }
335
336 104
                $fo = fopen($filename, 'r');
337 104
                $locked = flock($fo, LOCK_EX);
338 104
                if (!$locked) {
339
                    fclose($fo);
340
                    throw new QueueException('Can not delete file '.$filename);
341
                }
342 104
                $buf = file_get_contents($filename);
343 104
                if (empty($buf)) {
344
                    flock($fo, LOCK_UN);
345
                    fclose($fo);
346
                    throw new QueueException('File "'.$filename.'" is empty');
347
                }
348
                /**
349
                 * @var SmallFilesQueueSingleFile $data
350
                 */
351 104
                $data = @unserialize($buf);
352 104
                if (!is_object($data)) {
353
                    flock($fo, LOCK_UN);
354
                    fclose($fo);
355
                    throw new QueueException('File "'.$filename.'" does not contain Single Queue object');
356
                }
357 104
                if ($data->queue_name != $this->get_queue_name()) {
0 ignored issues
show
Bug introduced by
Accessing queue_name on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
358
                    flock($fo, LOCK_UN);
359
                    fclose($fo);
360
                    throw new QueueException('Invalid queue name ("'.$data->queue_name.
0 ignored issues
show
Bug introduced by
Accessing queue_name on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
361
                                             '" instead of "'.$this->get_queue_name().'")');
362
                }
363 104
                if ($data->version != self::SINGLE_FILE_DB_VERSION) {
0 ignored issues
show
Bug introduced by
Accessing version on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
364
                    flock($fo, LOCK_UN);
365
                    fclose($fo);
366
                    continue;
367
                }
368 104
                $data->time_last_update = microtime(true);
0 ignored issues
show
Bug introduced by
Accessing time_last_update on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
369
370 104
                $new_queue = [];
371 104
                foreach ($data->queue as $message) {
0 ignored issues
show
Bug introduced by
Accessing queue on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
372 104
                    $key = self::get_real_key_for_message($message);
373 104
                    if (!in_array($key, $filenames_contains_keys[$filename])) {
374 104
                        $message->is_read = true;
375 104
                        $new_queue[] = $message;
376 26
                    } else {
377 104
                        $deleted_keys[] = $key;
378
                    }
379 26
                }
380 104
                if (empty($new_queue)) {
381
                    // @hint На самом деле это невозможно
382 104
                    flock($fo, LOCK_UN);
383 104
                    fclose($fo);
384 104
                    if (!unlink($filename)) {
385
                        // @codeCoverageIgnoreStart
386
                        throw new QueueException('Can not delete file '.$filename.': '.
387
                                                 FileMutex::get_last_php_error_as_string());
388
                        // @codeCoverageIgnoreEnd
389
                    }
390 104
                    continue;
391
                }
392 104
                $data->queue = $new_queue;
0 ignored issues
show
Bug introduced by
Accessing queue on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
393 104
                $u = file_put_contents($filename, serialize($data));
394 104
                if ($u === false) {
395
                    // @codeCoverageIgnoreStart
396
                    throw new QueueException('Can not save single query file "'.$filename.'": '.
397
                                             FileMutex::get_last_php_error_as_string());
398
                    // @codeCoverageIgnoreEnd
399
                }
400 104
                flock($fo, LOCK_UN);
401 104
                fclose($fo);
402 78
            }
403
404 312
            return array_unique($deleted_keys);
405
        }
406
407
        /**
408
         * Обновляем сообщение и сразу же сохраняем всё
409
         *
410
         * Эта функция не рейзит ошибку, если сообщение не найдено
411
         *
412
         * @param iMessage|object $message
413
         * @param string|null     $key форсированно задаём ключ сообщения
414
         *
415
         * @return boolean
416
         * @throws QueueException
417
         */
418 320
        function update_message($message, $key = null) {
419 320
            $this_key = !is_null($key) ? $key : self::get_real_key_for_message($message);
420
421 320
            if (!isset($this->_key_to_file[$this_key])) {
422
                // Нет такого файла в списке
423 160
                return false;
424
            }
425 320
            $filename = $this->_key_to_file[$this_key];
426 320
            if (!file_exists($filename)) {
427
                return false;
428
            }
429 320
            if (!is_writable($filename)) {
430
                throw new QueueException('Can not update read only file');
431
            }
432
433 320
            $fo = fopen($filename, 'r');
434 320
            $locked = flock($fo, LOCK_EX);
435 320
            if (!$locked) {
436
                fclose($fo);
437
                throw new QueueException('Can not delete file '.$filename.': '.FileMutex::get_last_php_error_as_string());
438
            }
439 320
            $buf = file_get_contents($filename);
440 320
            if (empty($buf)) {
441
                flock($fo, LOCK_UN);
442
                fclose($fo);
443
                throw new QueueException('File "'.$filename.'" is empty');
444
            }
445
            // @todo обрабатывать ошибки
446
            /**
447
             * @var SmallFilesQueueSingleFile $data_in
448
             */
449 320
            $data_in = @unserialize($buf);
450 320
            if (!is_object($data_in)) {
451
                flock($fo, LOCK_UN);
452
                fclose($fo);
453
                throw new QueueException('File "'.$filename.'" does not contain Single Queue object');
454
            }
455 320
            if ($data_in->version != self::SINGLE_FILE_DB_VERSION) {
0 ignored issues
show
Bug introduced by
Accessing version on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
456
                flock($fo, LOCK_UN);
457
                fclose($fo);
458
                throw new QueueException('Single DB File version mismatch ('.$data_in->version.
0 ignored issues
show
Bug introduced by
Accessing version on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
459
                                         ' instead of '.self::SINGLE_FILE_DB_VERSION.')');
460
            }
461 320
            if ($data_in->queue_name != $this->get_queue_name()) {
0 ignored issues
show
Bug introduced by
Accessing queue_name on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
462
                flock($fo, LOCK_UN);
463
                fclose($fo);
464
                throw new QueueException('Invalid queue name ("'.$data_in->queue_name.
0 ignored issues
show
Bug introduced by
Accessing queue_name on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
465
                                         '" instead of "'.$this->get_queue_name().'")');
466
            }
467 320
            $data_in->time_last_update = microtime(true);
0 ignored issues
show
Bug introduced by
Accessing time_last_update on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
468
469
            // Ищем то же сообщение и заменяем его
470 320
            $exists = $this->change_message_in_array($data_in->queue, $message, $this_key);
0 ignored issues
show
Bug introduced by
Accessing queue on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
471 320
            if ($exists) {
472 320
                $u = file_put_contents($filename, serialize($data_in));
473 320
                if ($u === false) {
474
                    // @codeCoverageIgnoreStart
475
                    throw new QueueException('Can not save single query file "'.$filename.'": '.
476
                                             FileMutex::get_last_php_error_as_string());
477
                    // @codeCoverageIgnoreEnd
478
                }
479 80
            }
480 320
            flock($fo, LOCK_UN);
481 320
            fclose($fo);
482
483 320
            return $exists;
484
        }
485
486
        /**
487
         * Поддерживает ли очередь сортировку event'ов при вставке
488
         *
489
         * @return boolean
490
         */
491 4
        static function is_support_sorted_events() {
492 4
            return false;
493
        }
494
495
        /*
496
         * @param double|integer $wait_time
497
         *
498
         * @return iMessage|object|null
499
         *
500
         * @throws QueueException
501
         * @codeCoverageIgnore
502
         /
503
        protected function consume_next_message_with_inotify($wait_time = -1) {
504
            $start = microtime(true);
505
            // @todo написать
506
            throw new QueueException('Не готово');
507
        }
508
        */
509
510
        /*
511
         * @codeCoverageIgnore
512
         /
513
        function test_inotify() {
514
            // @todo этого тут быть не должно
515
            $a = inotify_init();
516
        }
517
        */
518
519
        /**
520
         * @param SmallFilesQueueTransport $queue
521
         *
522
         * @return boolean
523
         */
524 340
        function is_equal_to($queue) {
525 340
            if (spl_object_hash($this) == spl_object_hash($queue)) {
526 4
                return true;
527
            }
528 340
            if (!parent::is_equal_to($queue)) {
529 152
                return false;
530
            }
531
532 188
            return (($queue->_message_folder == $this->_message_folder) and
533 188
                    ($queue->get_queue_name() == $this->get_queue_name()));
534
        }
535
    }
536
537
?>