Completed
Push — developer ( dc3c7c...6e5def )
by Никита
15:38
created

Queue::delete_messages()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 6
cts 6
cp 1
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
crap 2
1
<?php
2
3
    namespace NokitaKaze\Queue;
4
5
    class Queue extends AbstractQueueTransport {
6
        const ProducerThreadCount = 5;
7
        const DefaultDBFileCount = 10;
8
        const DefaultMessageFolderSubfolderCount = 10;
9
10
        const StorageTemporary = 0;
11
        const StoragePersistent = 1;
12
13
        /**
14
         * @var QueueTransport
15
         */
16
        protected $_general_queue = null;
17
18
        /**
19
         * @var QueueTransport[]
20
         */
21
        protected $_additional_queue = [];
22
23
        /**
24
         * @var GeneralQueueConstructionSettings|object $_settings
25
         */
26
        protected $_settings = null;
27
28
        /**
29
         * SmartQueue constructor.
30
         *
31
         * @param GeneralQueueConstructionSettings|object $settings
32
         *
33
         * @throws QueueException
34
         */
35 27
        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...
36 27
            $this->_settings = $settings;
37 27
            foreach ($settings->queues as $queue_settings) {
38
                /**
39
                 * @var string|QueueTransport $queue_class_name
40
                 * @var QueueTransport        $queue
41
                 */
42 27
                if (substr($queue_settings->class_name, 0, 1) == '\\') {
43
                    $queue_class_name = $queue_settings->class_name.'QueueTransport';
44
                } else {
45 27
                    $queue_class_name = __NAMESPACE__.'\\'.$queue_settings->class_name.'QueueTransport';
46
                }
47 27
                $queue = new $queue_class_name($queue_settings);
48
49 27
                if (isset($queue_settings->is_general) and $queue_settings->is_general) {
50 27
                    if (isset($this->_general_queue)) {
51
                        throw new QueueException('Two or more general queues');
52
                    }
53 27
                    $this->_general_queue = $queue;
54 27
                    $this->_additional_queue[] = clone $queue;
55 9
                } else {
56 24
                    $this->_additional_queue[] = $queue;
57
                }
58 9
            }
59 27
            if (is_null($this->_general_queue)) {
60
                throw new QueueException('Can not get general queue');
61
            }
62
            // @todo дописать
63 27
        }
64
65
        /**
66
         * @return string
67
         */
68 3701
        static function generate_rnd_postfix() {
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...
69
            // mt_rand. **ДЁШЕВО** и сердито
70 3701
            return mt_rand(1000000, 9999999).mt_rand(1000000, 9999999);
71
72
            // return RandomString::generate(6, RandomString::INCLUDE_NUMERIC | RandomString::INCLUDE_LOWER_LETTERS);
73
        }
74
75
        /**
76
         * Формируем сообщение для очереди
77
         *
78
         * @param mixed       $data
79
         * @param string|null $name Название сообщения. Если null, то можно дублировать
80
         * @param integer     $sort
81
         *
82
         * @return iMessage|object
83
         */
84 3702
        static function build_message($data, $name = null, $sort = 5) {
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...
85
            return (object) [
86 3702
                'name' => is_null($name) ? null : (string) $name,
87 3702
                'data' => $data,
88 3702
                'time_created' => microtime(true),
89 3702
                'time_rnd_postfix' => is_null($name) ? static::generate_rnd_postfix() : null,
90 3702
                'time_last_update' => microtime(true),
91 3702
                'sort' => min(max($sort, 0), self::DefaultDBFileCount - 1),
92 1205
                'is_read' => false,
93 1205
            ];
94
        }
95
96
        /**
97
         * @param iMessage|object $object
98
         *
99
         * @return iMessage|object
100
         * @throws QueueException
101
         */
102 3699
        static function sanify_event_object($object) {
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...
103 3699
            $ret = clone $object;
104
            /** @noinspection PhpParamsInspection */
105 3699
            if (!array_key_exists('name', $ret)) {
106 3
                $ret->name = null;
107 1
            }
108
            /** @noinspection PhpParamsInspection */
109 3699
            if (!array_key_exists('data', $ret)) {
110 3
                throw new QueueException('Datum does not have field data', 12);
111
            }
112 3699
            if (!isset($ret->sort)) {
113 3
                $ret->sort = 5;
114 1
            } else {
115 3696
                $ret->sort = min(max($ret->sort, 0), Queue::DefaultDBFileCount - 1);
116
            }
117
118 3699
            return $ret;
119
        }
120
121
        /**
122
         * Cloning sub queues
123
         */
124 1266
        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...
125 1266
            parent::__clone();
126 1266
            $this->_general_queue = clone $this->_general_queue;
127 1266
            foreach ($this->_additional_queue as &$sub_queue) {
128 1266
                $sub_queue = clone $sub_queue;
129 422
            }
130 1266
        }
131
132
        /**
133
         * implements Transport
134
         */
135
136
        /**
137
         * @param iMessage|object $message
138
         *
139
         * @return string
140
         */
141 3822
        static function get_real_key_for_message($message) {
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...
142 3822
            return !is_null($message->name)
143 3737
                ? $message->name
144 3799
                : sprintf('_%s%s',
145 3788
                    number_format($message->time_created, 7, '.', ''),
146 3811
                    isset($message->time_rnd_postfix) ? '_'.$message->time_rnd_postfix : ''
147 1245
                );
148
        }
149
150 6
        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...
151 6
            return $this->_settings->name;
152
        }
153
154 3
        static function is_support_sorted_events() {
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...
155 3
            return false;
156
        }
157
158 15
        function produce_message($data, $name = null, $sort = 5) {
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...
159 15
            $this->set_same_time_flag(1);
160 15
            $this->_general_queue->produce_message($data, $name, $sort);
161 15
        }
162
163 1245
        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...
164 1245
            $this->set_same_time_flag(1);
165 1245
            $this->_general_queue->push($this->_pushed_for_save);
166 1245
            $this->_pushed_for_save = [];
167 1245
            $this->_general_queue->save();
168 1245
        }
169
170
        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...
171
            $this->_general_queue->set_exclusive_mode($mode);
172
            foreach ($this->_additional_queue as $queue) {
173
                $queue->set_exclusive_mode($mode);
174
            }
175
        }
176
177
        /**
178
         * @var iMessage[]|object[]
179
         */
180
        protected $_next_messages = [];
181
182 1254
        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...
183 1254
            $this->set_same_time_flag(2);
184 1254
            if (!empty($this->_next_messages)) {
185 1143
                return array_shift($this->_next_messages);
186
            }
187 1254
            $ts_start = microtime(true);
188 1254
            $till_time = $ts_start + $wait_time;
189
190 1254
            $first_run = false;
191
            do {
192 1254
                if ($first_run) {
193 24
                    usleep($this->_settings->sleep_time_while_consuming * 1000000);
194 8
                } else {
195 1254
                    $first_run = true;
196
                }
197 1254
                $messages = [];
198 1254
                foreach ($this->_additional_queue as $queue) {
199 1254
                    while ($message = $queue->consume_next_message(0)) {
200 1254
                        $key = self::get_real_key_for_message($message);
201 1254
                        if (isset($this->_consumed_keys[$key])) {
202 1230
                            continue;
203
                        }
204 1254
                        $message->is_read = true;
205 1254
                        $messages[] = $message;
206 1254
                        $this->_consumed_keys[$key] = 1;
207 418
                    }
208
209 1254
                    if (!empty($messages)) {
210 1254
                        $this->_next_messages = $messages;
211 1254
                        if (!$queue->is_equal_to($this->_general_queue)) {
212 1242
                            $this->_general_queue->push($messages);
213 1242
                            $this->_general_queue->save();
214 1242
                            $queue->delete_messages($messages);
215 414
                        }
216
217 1254
                        return array_shift($this->_next_messages);
218
                    }
219 417
                }
220 1239
                unset($message, $key, $queue);
221 1239
            } while (($wait_time == -1) or (microtime(true) <= $till_time));
222
223 1239
            return null;
224
        }
225
226
        /**
227
         * Обновляем сообщение и сразу же сохраняем всё
228
         *
229
         * Эта функция не рейзит ошибку, если сообщение не найдено
230
         *
231
         * @param iMessage|object $message
232
         * @param string|null     $key форсированно задаём ключ сообщения
233
         *
234
         * @return boolean
235
         * @throws QueueException
236
         */
237 120
        function update_message($message, $key = null) {
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...
238 120
            $this_key = !is_null($key) ? $key : self::get_real_key_for_message($message);
239 120
            foreach ($this->_next_messages as $exists_message) {
240
                if (self::get_real_key_for_message($exists_message) == $this_key) {
241
                    $exists_message->data = $message->data;
242
                    $exists_message->time_last_update = microtime(true);
243
                    break;
244
                }
245 40
            }
246
247 120
            return $this->_general_queue->update_message($message, $key);
248
        }
249
250 3
        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...
251 3
            $this->_consumed_keys = [];
252 3
            foreach ($this->_additional_queue as $queue) {
253 3
                $queue->clear_consumed_keys();
254 1
            }
255 3
        }
256
257
        /**
258
         * Удалить сообщения и сразу же записать это в БД
259
         *
260
         * @param iMessage[]|object[] $messages
261
         *
262
         * @return string[]|integer[]
263
         */
264 1092
        function delete_messages(array $messages) {
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...
265 1092
            $deleted_keys = [];
266 1092
            foreach ($this->_additional_queue as $queue) {
267 1092
                $deleted_keys = array_merge($deleted_keys, $queue->delete_messages($messages));
268 364
            }
269
270 1092
            return array_unique($deleted_keys);
271
        }
272
273
        /**
274
         * @param Queue $queue
275
         *
276
         * @return boolean
277
         */
278 3
        function is_equal_to($queue) {
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...
279 3
            if (spl_object_hash($this) == spl_object_hash($queue)) {
280 3
                return true;
281
            }
282 3
            if (!parent::is_equal_to($queue)) {
283
                return false;
284
            }
285 3
            if (!$this->_general_queue->is_equal_to($queue->_general_queue)) {
286
                return false;
287
            }
288 3
            foreach ($this->_additional_queue as $i => $sub_queue) {
289 3
                if (!$sub_queue->is_equal_to($queue->_additional_queue[$i])) {
290 2
                    return false;
291
                }
292 1
            }
293
294 3
            return true;
295
        }
296
    }
297
298
?>