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

Queue   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 292
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 88.06%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 50
c 1
b 0
f 0
lcom 1
cbo 3
dl 0
loc 292
ccs 118
cts 134
cp 0.8806
rs 8.6206

16 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 29 7
A generate_rnd_postfix() 0 6 1
A build_message() 0 11 3
A sanify_event_object() 0 18 4
A __clone() 0 7 2
A get_real_key_for_message() 0 8 3
A get_queue_name() 0 3 1
A is_support_sorted_events() 0 3 1
A produce_message() 0 4 1
A save() 0 6 1
A set_exclusive_mode() 0 6 2
D consume_next_message() 0 43 10
A update_message() 0 12 4
A clear_consumed_keys() 0 6 2
A delete_messages() 0 8 2
B is_equal_to() 0 18 6

How to fix   Complexity   

Complex Class

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

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 6
        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 6
            $this->_settings = $settings;
37 6
            foreach ($settings->queues as $queue_settings) {
38
                /**
39
                 * @var string|QueueTransport $queue_class_name
40
                 * @var QueueTransport        $queue
41
                 */
42 6
                if (substr($queue_settings->class_name, 0, 1) == '\\') {
43
                    $queue_class_name = $queue_settings->class_name.'QueueTransport';
44
                } else {
45 6
                    $queue_class_name = __NAMESPACE__.'\\'.$queue_settings->class_name.'QueueTransport';
46
                }
47 6
                $queue = new $queue_class_name($queue_settings);
48
49 6
                if (isset($queue_settings->is_general) and $queue_settings->is_general) {
50 6
                    if (isset($this->_general_queue)) {
51
                        throw new QueueException('Two or more general queues');
52
                    }
53 6
                    $this->_general_queue = $queue;
54 6
                    $this->_additional_queue[] = clone $queue;
55 2
                } else {
56 6
                    $this->_additional_queue[] = $queue;
57
                }
58 2
            }
59 6
            if (is_null($this->_general_queue)) {
60
                throw new QueueException('Can not get general queue');
61
            }
62
            // @todo дописать
63 6
        }
64
65
        /**
66
         * @return string
67
         */
68
        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
            return mt_rand(1000000, 9999999).mt_rand(1000000, 9999999);
71
72
            // return RandomString::generate(6, RandomString::INCLUDE_NUMERIC | RandomString::INCLUDE_LOWER_LETTERS);
73
        }
74 3678
75
        /**
76 3678
         * Формируем сообщение для очереди
77 3678
         *
78 3678
         * @param mixed       $data
79 3678
         * @param string|null $name Название сообщения. Если null, то можно дублировать
80 3678
         * @param integer     $sort
81 1221
         *
82 1221
         * @return iMessage|object
83
         */
84
        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
                'name' => is_null($name) ? null : (string) $name,
87
                'data' => $data,
88
                'time_created' => microtime(true),
89
                'time_rnd_postfix' => is_null($name) ? static::generate_rnd_postfix() : null,
90
                'time_last_update' => microtime(true),
91 3678
                'sort' => min(max($sort, 0), self::DefaultDBFileCount - 1),
92 3678
                'is_read' => false,
93
            ];
94 3678
        }
95 3
96 1
        /**
97
         * @param iMessage|object $object
98 3678
         *
99 3
         * @return iMessage|object
100
         * @throws QueueException
101 3678
         */
102 3
        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 1
            $ret = clone $object;
104 3675
            /** @noinspection PhpParamsInspection */
105
            if (!array_key_exists('name', $ret)) {
106
                $ret->name = null;
107 3678
            }
108
            /** @noinspection PhpParamsInspection */
109
            if (!array_key_exists('data', $ret)) {
110
                throw new QueueException('Datum does not have field data', 12);
111
            }
112
            if (!isset($ret->sort)) {
113 1266
                $ret->sort = 5;
114 1266
            } else {
115 1266
                $ret->sort = min(max($ret->sort, 0), Queue::DefaultDBFileCount - 1);
116 1266
            }
117 1266
118 422
            return $ret;
119 1266
        }
120
121
        /**
122
         * Cloning sub queues
123
         */
124
        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
            parent::__clone();
126
            $this->_general_queue = clone $this->_general_queue;
127
            foreach ($this->_additional_queue as &$sub_queue) {
128
                $sub_queue = clone $sub_queue;
129
            }
130 3672
        }
131 3672
132
        /**
133
         * implements Transport
134 6
         */
135 6
136
        /**
137
         * @param iMessage|object $message
138 3
         *
139 3
         * @return string
140
         */
141
        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 15
            return !is_null($message->name)
143 15
                ? $message->name
144 15
                : sprintf('_%s%s',
145 15
                    number_format($message->time_created, 7, '.', ''),
146
                    isset($message->time_rnd_postfix) ? '_'.$message->time_rnd_postfix : ''
147 1224
                );
148 1224
        }
149 1224
150 1224
        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 1224
            return $this->_settings->name;
152 1224
        }
153
154
        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
            return false;
156
        }
157
158
        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
            $this->set_same_time_flag(1);
160
            $this->_general_queue->produce_message($data, $name, $sort);
161
        }
162
163
        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
            $this->set_same_time_flag(1);
165
            $this->_general_queue->push($this->_pushed_for_save);
166 1254
            $this->_pushed_for_save = [];
167 1254
            $this->_general_queue->save();
168 1254
        }
169 1122
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 1254
            $this->_general_queue->set_exclusive_mode($mode);
172 1254
            foreach ($this->_additional_queue as $queue) {
173
                $queue->set_exclusive_mode($mode);
174 1254
            }
175
        }
176 1254
177 24
        /**
178 8
         * @var iMessage[]|object[]
179 1254
         */
180
        protected $_next_messages = [];
181 1254
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 1233
            if (!empty($this->_next_messages)) {
185 1233
                return array_shift($this->_next_messages);
186 1218
            }
187
            $ts_start = microtime(true);
188 1233
            $till_time = $ts_start + $wait_time;
189 1233
190 1233
            $first_run = false;
191 411
            do {
192
                if ($first_run) {
193 1254
                    usleep($this->_settings->sleep_time_while_consuming * 1000000);
194 1233
                } else {
195 1233
                    $first_run = true;
196 1230
                }
197 1230
                $messages = [];
198 1230
                foreach ($this->_additional_queue as $queue) {
199 410
                    while ($message = $queue->consume_next_message(0)) {
200
                        $key = self::get_real_key_for_message($message);
201 1247
                        if (isset($this->_consumed_keys[$key])) {
202
                            continue;
203 417
                        }
204 1239
                        $message->is_read = true;
205 1239
                        $messages[] = $message;
206
                        $this->_consumed_keys[$key] = 1;
207 1239
                    }
208
209
                    if (!empty($messages)) {
210
                        $this->_next_messages = $messages;
211
                        if (!$queue->is_equal_to($this->_general_queue)) {
212
                            $this->_general_queue->push($messages);
213
                            $this->_general_queue->save();
214
                            $queue->delete_messages($messages);
215
                        }
216
217
                        return array_shift($this->_next_messages);
218
                    }
219
                }
220
                unset($message, $key, $queue);
221 120
            } while (($wait_time == -1) or (microtime(true) <= $till_time));
222 120
223 120
            return null;
224
        }
225
226
        /**
227
         * Обновляем сообщение и сразу же сохраняем всё
228
         *
229 40
         * Эта функция не рейзит ошибку, если сообщение не найдено
230
         *
231 120
         * @param iMessage|object $message
232
         * @param string|null     $key форсированно задаём ключ сообщения
233
         *
234 3
         * @return boolean
235 3
         * @throws QueueException
236 3
         */
237 3
        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 1
            $this_key = !is_null($key) ? $key : self::get_real_key_for_message($message);
239 3
            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
            }
246
247
            return $this->_general_queue->update_message($message, $key);
248 1092
        }
249 1092
250 1092
        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 1092
            $this->_consumed_keys = [];
252 364
            foreach ($this->_additional_queue as $queue) {
253
                $queue->clear_consumed_keys();
254 1092
            }
255
        }
256
257
        /**
258
         * Удалить сообщения и сразу же записать это в БД
259
         *
260
         * @param iMessage[]|object[] $messages
261
         *
262 3
         * @return string[]|integer[]
263 3
         */
264 3
        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
            $deleted_keys = [];
266 3
            foreach ($this->_additional_queue as $queue) {
267
                $deleted_keys = array_merge($deleted_keys, $queue->delete_messages($messages));
268
            }
269 3
270
            return array_unique($deleted_keys);
271
        }
272 3
273 3
        /**
274 2
         * @param Queue $queue
275
         *
276 1
         * @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
            if (spl_object_hash($this) == spl_object_hash($queue)) {
280
                return true;
281
            }
282
            if (!parent::is_equal_to($queue)) {
283
                return false;
284
            }
285
            if (!$this->_general_queue->is_equal_to($queue->_general_queue)) {
286
                return false;
287
            }
288
            foreach ($this->_additional_queue as $i => $sub_queue) {
289
                if (!$sub_queue->is_equal_to($queue->_additional_queue[$i])) {
290
                    return false;
291
                }
292
            }
293
294
            return true;
295
        }
296
    }
297
298
?>