Completed
Push — developer ( 2584f0...ccb49a )
by Никита
02:19
created

SmallFilesQueueTransport::test_inotify()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 1
cts 1
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
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 15
         */
31 15
        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 3
            if (!isset($settings->message_folder)) {
33
                throw new QueueException('message_folder has not been set');
34 12
            }
35 3
            if (!isset($settings->name)) {
36
                throw new QueueException('name has not been set');
37 9
            }
38 9
            $this->_message_folder = $settings->message_folder;
39 9
            $this->_queue_name = $settings->name;
40
            if (isset($settings->message_folder_subfolder_count)) {
41
                $this->_message_folder_subfolder_count = $settings->message_folder_subfolder_count;
42 9
            }
43
            if (isset($settings->is_inotify_enabled)) {
44
                $this->_is_inotify_enabled = $settings->is_inotify_enabled;
45 9
            } else {
46
                $this->_is_inotify_enabled = function_exists('inotify_init');
47 9
            }
48
            $this->_chunk_file_postfix = '_'.static::generate_rnd_postfix();
49
        }
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 2496
         * @return string
61 2496
         */
62
        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
            return $this->_queue_name;
64 2481
        }
65 2481
66 2481
        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 12
            $this->set_same_time_flag(1);
68
            if (empty($this->_pushed_for_save)) {
69
                return;
70
            }
71
72
            /**
73 2481
             * @var SmallFilesQueueSingleFile $data
74 2481
             */
75 2481
            $data = (object) [];
76 2481
            $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 2481
            $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 2481
            $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 2481
            $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 2481
            $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 2481
            $num = mt_rand(0, $this->_message_folder_subfolder_count - 1);
82 2481
            $folder = $this->_message_folder.'/'.$num;
83
            FileMutex::create_folders_in_path($folder);
84 2481
            $filename = sprintf('%s/smartqueue_%s%s.chunk.dat',
85 2481
                $folder, number_format(microtime(true), 4, '.', ''), $this->_chunk_file_postfix);
86
87
            $u = file_put_contents($filename, serialize($data), LOCK_EX);
88
            if ($u === false) {
89
                // @codeCoverageIgnoreStart
90 2481
                throw new QueueException('Can not save queue to a file');
91 2481
                // @codeCoverageIgnoreEnd
92 827
            }
93 2481
            foreach ($this->_pushed_for_save as $message) {
94 2481
                $this->_key_to_file[static::get_real_key_for_message($message)] = $filename;
95
            }
96
            $this->_pushed_for_save = [];
97
        }
98
99
        /**
100
         * @param double|integer $wait_time
101
         *
102 2511
         * @return iMessage|object|null
103 2511
         * @throws QueueException
104 2511
         */
105 1881
        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
            $this->set_same_time_flag(2);
107
            if (!empty($this->_last_consumed_messages)) {
108 2511
                return array_shift($this->_last_consumed_messages);
109
            }
110
111
            return $this->consume_next_message_without_inotify($wait_time);
112
            /*
113 2511
            if ($this->_is_inotify_enabled and false) {// @todo добавить Inotify
114
                // @codeCoverageIgnoreStart
115
                return $this->consume_next_message_with_inotify($wait_time);
116
                // @codeCoverageIgnoreEnd
117 6
            } else {
118 6
                return $this->consume_next_message_without_inotify($wait_time);
119 6
            }
120 6
            */
121 6
        }
122
123 2541
        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 2541
            parent::clear_consumed_keys();
125 2541
            $this->_last_consumed_messages = [];
126
            $this->_consumed_filenames = [];
127 847
        }
128 2541
129
        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
            parent::__clone();
131
            foreach ($this->_last_consumed_messages as &$message) {
132
                $message = clone $message;
133
            }
134
        }
135
136 2511
        /**
137 2511
         * @param double|integer $wait_time
138
         *
139 2511
         * @return iMessage|object|null
140 2511
         * @throws QueueException
141 2511
         */
142 2472
        protected function consume_next_message_without_inotify($wait_time = -1) {
143
            $start = microtime(true);
144 2481
            do {
145 2481
                for ($i = 0; $i < $this->_message_folder_subfolder_count; $i++) {
146 2481
                    $folder = $this->_message_folder.'/'.$i;
147
                    if (!file_exists($folder) or !is_readable($folder) or !is_dir($folder)) {
148 2481
                        continue;
149 2481
                    }
150
                    foreach (scandir($folder) as $f) {
151
                        if (in_array($f, ['.', '..']) or !preg_match('|smartqueue_[0-9.]+(_[a-z0-9]+)?\\.chunk\\.dat$|', $f)) {
152 2481
                            continue;
153 2466
                        }
154
                        $filename = $folder.'/'.$f;
155 2481
                        if (is_dir($filename) or !is_readable($filename)) {
156 2481
                            continue;
157 2481
                        }
158
                        if (isset($this->_consumed_filenames[$filename])) {
159
                            continue;
160
                        }
161
                        $fi = fopen($filename, 'r');
162 2481
                        $locked = flock($fi, LOCK_EX | LOCK_NB);
163
                        if (!$locked) {
164
                            fclose($fi);
165
                            continue;
166 2481
                        }
167 2481
168
                        $buf = file_get_contents($filename);
169
                        /**
170
                         * @var SmallFilesQueueSingleFile $file_data
171
                         */
172
                        $file_data = @unserialize($buf);
173 2481
                        if (!is_object($file_data)) {
174
                            // File does not contain Single Queue object
175
                            flock($fi, LOCK_UN);
176
                            fclose($fi);
177
                            continue;
178 2481
                        }
179
                        if ($file_data->queue_name != $this->get_queue_name()) {
180
                            flock($fi, LOCK_UN);
181
                            fclose($fi);
182
                            continue;
183
                        }
184 2481
                        if ($file_data->version != self::SINGLE_FILE_DB_VERSION) {
185 2481
                            flock($fi, LOCK_UN);
186 2481
                            fclose($fi);
187 2481
                            continue;
188 6
                        }
189
190
                        $this->_last_consumed_messages = [];
191 2481
                        foreach ($file_data->queue as $message) {
192 2481
                            $key = self::get_real_key_for_message($message);
193 2481
                            if (isset($this->_consumed_keys[$key])) {
194 2481
                                continue;
195 2481
                            }
196 827
197 2481
                            $message->time_consumed = microtime(true);
198 2481
                            $message->queue = $this;
199 2481
                            $this->_key_to_file[$key] = $filename;
200 2481
                            $this->_last_consumed_messages[] = $message;
201 2481
                            $this->_consumed_keys[$key] = 1;
202
                        }
203 822
                        flock($fi, LOCK_UN);
204 822
                        fclose($fi);
205 2496
                        $this->_consumed_filenames[$filename] = 1;
206
                        if (!empty($this->_last_consumed_messages)) {
207 2496
                            return array_shift($this->_last_consumed_messages);
208
                        }
209
                    }
210
                }
211
            } while (($wait_time == -1) or ($start + $wait_time >= microtime(true)));
212
213 2340
            return null;
214 2340
        }
215 2340
216 2340
        /**
217 2340
         * @param iMessage[]|object[] $messages
218 780
         */
219 780
        protected function copy_key_to_file_from_messages(array $messages) {
220 780
            foreach ($messages as $message) {
221 2340
                if (isset($message->queue) and (get_class($message->queue) == self::class)) {
222
                    foreach ($message->queue->_key_to_file as $key => $filename) {
223
                        $this->_key_to_file[$key] = $filename;
224
                    }
225
                }
226
            }
227
        }
228 2340
229 2340
        /**
230 2340
         * @param iMessage[]|object[] $messages
231 2340
         *
232 2340
         * @return array[]
233 2340
         */
234 2340
        protected function get_filenames_from_messages(array $messages) {
235 2202
            $this->copy_key_to_file_from_messages($messages);
236
            $filenames = [];
237 2340
            $filenames_contains_keys = [];
238 2340
            foreach ($messages as $message) {
239 2340
                $key = self::get_real_key_for_message($message);
240 2340
                if (!isset($this->_key_to_file[$key])) {
241 780
                    continue;
242
                }
243 2340
                $filename = $this->_key_to_file[$key];
244 780
                $filenames[] = $filename;
245
                if (!isset($filenames_contains_keys[$filename])) {
246 2340
                    $filenames_contains_keys[$filename] = [];
247
                }
248
249
                $filenames_contains_keys[$filename][] = $key;
250
            }
251
252
            return [$filenames, $filenames_contains_keys];
253
        }
254
255
        /**
256
         * Удалить сообщения и сразу же записать это в БД
257 2340
         *
258
         * @param iMessage[]|object[] $messages
259
         *
260
         * @return string[]|integer[]
261
         * @throws QueueException
262 2340
         */
263 2340
        function delete_messages(array $messages) {
264 2340
            /**
265 2340
             * @var string[][] $filenames_contains_keys
266 1761
             * @var string[]   $filenames
267 587
             */
268 2340
            list($filenames, $filenames_contains_keys) = $this->get_filenames_from_messages($messages);
269
            $filenames_contains_keys_all = [];
270 780
            foreach ($this->_key_to_file as $key => $filename) {
271 2340
                if (isset($filenames_contains_keys_all[$filename])) {
272
                    $filenames_contains_keys_all[$filename][] = $key;
273 2340
                } else {
274 2340
                    $filenames_contains_keys_all[$filename] = [$key];
275 2340
                }
276 1800
            }
277 1800
            unset($key, $filename);
278
279 2340
            $deleted_keys = [];
280
            foreach ($filenames as $filename) {
281
                if (!file_exists($filename)) {
282 2340
                    // @todo Надо подумать правильный ли это подход
283
                    // Тут будут все ключи, а не только те, которые надо было удалить
284 1794
                    $deleted_keys = array_merge($deleted_keys, $filenames_contains_keys[$filename]);
285
                    continue;
286
                }
287
                if (!is_writable($filename)) {
288
                    throw new QueueException('Can not delete messages from read only files');
289 1794
                }
290 1794
                if (count($filenames_contains_keys[$filename]) == count($filenames_contains_keys_all[$filename])) {
291
                    // Нужно удалить все записи в файле, значит можно просто удалить файл целиком
292
                    if (!unlink($filename)) {
293 606
                        // @codeCoverageIgnoreStart
294 606
                        throw new QueueException('Can not delete file '.$filename);
295 606
                        // @codeCoverageIgnoreEnd
296
                    }
297
                    $deleted_keys = array_merge($deleted_keys, $filenames_contains_keys[$filename]);
298
                    continue;
299 606
                }
300 606
301
                $fo = fopen($filename, 'r');
302
                $locked = flock($fo, LOCK_EX);
303
                if (!$locked) {
304
                    fclose($fo);
305
                    throw new QueueException('Can not delete file '.$filename);
306
                }
307
                $buf = file_get_contents($filename);
308 606
                if (empty($buf)) {
309 606
                    flock($fo, LOCK_UN);
310
                    fclose($fo);
311
                    throw new QueueException('File "'.$filename.'" is empty');
312
                }
313
                /**
314 606
                 * @var SmallFilesQueueSingleFile $data
315
                 */
316
                $data = @unserialize($buf);
317
                if (!is_object($data)) {
318
                    flock($fo, LOCK_UN);
319
                    fclose($fo);
320 606
                    throw new QueueException('File "'.$filename.'" does not contain Single Queue object');
321
                }
322
                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...
323
                    flock($fo, LOCK_UN);
324
                    fclose($fo);
325 606
                    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...
326
                                             '" instead of "'.$this->get_queue_name().'")');
327 606
                }
328 606
                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...
329 606
                    flock($fo, LOCK_UN);
330 606
                    fclose($fo);
331 606
                    continue;
332 606
                }
333 202
                $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...
334 606
335
                $new_queue = [];
336 202
                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...
337 606
                    $key = self::get_real_key_for_message($message);
338
                    if (!in_array($key, $filenames_contains_keys[$filename])) {
339 606
                        $message->is_read = true;
340 606
                        $new_queue[] = $message;
341 606
                    } else {
342
                        $deleted_keys[] = $key;
343
                    }
344
                }
345
                if (empty($new_queue)) {
346 606
                    // @hint На самом деле это невозможно
347
                    flock($fo, LOCK_UN);
348 606
                    fclose($fo);
349 606
                    if (!unlink($filename)) {
350 606
                        // @codeCoverageIgnoreStart
351
                        throw new QueueException('Can not delete file '.$filename);
352
                        // @codeCoverageIgnoreEnd
353
                    }
354
                    continue;
355 606
                }
356 606
                $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...
357 780
                $u = file_put_contents($filename, serialize($data));
358
                if ($u === false) {
359 2340
                    // @codeCoverageIgnoreStart
360
                    throw new QueueException('Can not save single query file "'.$filename.'"');
361
                    // @codeCoverageIgnoreEnd
362
                }
363
                flock($fo, LOCK_UN);
364
                fclose($fo);
365
            }
366
367
            return array_unique($deleted_keys);
368
        }
369
370
        /**
371
         * Обновляем сообщение и сразу же сохраняем всё
372
         *
373 240
         * Эта функция не рейзит ошибку, если сообщение не найдено
374 240
         *
375
         * @param iMessage|object $message
376 240
         * @param string|null     $key форсированно задаём ключ сообщения
377
         *
378 120
         * @return boolean
379
         * @throws QueueException
380 240
         */
381 240
        function update_message($message, $key = null) {
382
            $this_key = !is_null($key) ? $key : self::get_real_key_for_message($message);
383
384 240
            if (!isset($this->_key_to_file[$this_key])) {
385
                // Нет такого файла в списке
386
                return false;
387
            }
388 240
            $filename = $this->_key_to_file[$this_key];
389 240
            if (!file_exists($filename)) {
390 240
                return false;
391
            }
392
            if (!is_readable($filename)) {
393
                throw new QueueException('Can not update read only file');
394 240
            }
395 240
396
            $fo = fopen($filename, 'r');
397
            $locked = flock($fo, LOCK_EX);
398
            if (!$locked) {
399
                fclose($fo);
400
                throw new QueueException('Can not delete file '.$filename);
401
            }
402
            $buf = file_get_contents($filename);
403
            if (empty($buf)) {
404 240
                flock($fo, LOCK_UN);
405 240
                fclose($fo);
406
                throw new QueueException('File "'.$filename.'" is empty');
407
            }
408
            // @todo обрабатывать ошибки
409
            /**
410 240
             * @var SmallFilesQueueSingleFile $data_in
411
             */
412
            $data_in = @unserialize($buf);
413
            if (!is_object($data_in)) {
414
                flock($fo, LOCK_UN);
415
                fclose($fo);
416 240
                throw new QueueException('File "'.$filename.'" does not contain Single Queue object');
417
            }
418
            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...
419
                flock($fo, LOCK_UN);
420
                fclose($fo);
421
                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...
422 240
                                         ' instead of '.self::SINGLE_FILE_DB_VERSION.')');
423
            }
424
            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...
425 240
                flock($fo, LOCK_UN);
426 240
                fclose($fo);
427 240
                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...
428 240
                                         '" instead of "'.$this->get_queue_name().'")');
429
            }
430
            $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...
431
432
            // Ищем то же сообщение и заменяем его
433 80
            $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...
434 240
            if ($exists) {
435 240
                $u = file_put_contents($filename, serialize($data_in));
436
                if ($u === false) {
437 240
                    // @codeCoverageIgnoreStart
438
                    throw new QueueException('Can not save single query file "'.$filename.'"');
439
                    // @codeCoverageIgnoreEnd
440
                }
441
            }
442
            flock($fo, LOCK_UN);
443
            fclose($fo);
444
445 3
            return $exists;
446 3
        }
447
448
        /**
449
         * Поддерживает ли очередь сортировку event'ов при вставке
450
         *
451
         * @return boolean
452
         */
453
        static function is_support_sorted_events() {
454
            return false;
455
        }
456
457
        /*
458
         * @param double|integer $wait_time
459
         *
460
         * @return iMessage|object|null
461
         *
462
         * @throws QueueException
463
         * @codeCoverageIgnore
464
         /
465
        protected function consume_next_message_with_inotify($wait_time = -1) {
466
            $start = microtime(true);
467
            // @todo написать
468
            throw new QueueException('Не готово');
469
        }
470
        */
471
472
        /*
473
         * @codeCoverageIgnore
474
         /
475
        function test_inotify() {
476 1236
            // @todo этого тут быть не должно
477 1236
            $a = inotify_init();
478 3
        }
479
        */
480 1236
481 1230
        /**
482
         * @param SmallFilesQueueTransport $queue
483
         *
484 6
         * @return boolean
485 6
         */
486
        function is_equal_to($queue) {
487
            if (spl_object_hash($this) == spl_object_hash($queue)) {
488
                return true;
489
            }
490
            if (!parent::is_equal_to($queue)) {
491
                return false;
492
            }
493
494
            return (($queue->_message_folder == $this->_message_folder) and
495
                    ($queue->get_queue_name() == $this->get_queue_name()));
496
        }
497
    }
498
499
?>