Passed
Pull Request — master (#16)
by Nikolay
13:10 queued 02:12
created

CallDetailRecordsController::getNewRecordsAction()   F

Complexity

Conditions 24
Paths 15450

Size

Total Lines 135
Code Lines 98

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 98
c 0
b 0
f 0
dl 0
loc 135
rs 0
cc 24
nc 15450
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Copyright © MIKO LLC - All Rights Reserved
4
 * Unauthorized copying of this file, via any medium is strictly prohibited
5
 * Proprietary and confidential
6
 * Written by Alexey Portnov, 6 2020
7
 */
8
9
namespace MikoPBX\AdminCabinet\Controllers;
10
11
use DateTime;
12
use MikoPBX\Common\Models\{CallDetailRecords, PbxSettings};
13
14
class CallDetailRecordsController extends BaseController
15
{
16
17
18
    /**
19
     * Выборка записей из журнала звонков
20
     *
21
     */
22
    public function indexAction(): void
23
    {
24
    }
25
26
    /**
27
     * Запрос нового пакета истории разговоров для DataTable JSON
28
     */
29
    public function getNewRecordsAction(): void
30
    {
31
        $currentPage                 = $this->request->getPost('draw');
32
        $position                    = $this->request->getPost('start');
33
        $recordsPerPage              = $this->request->getPost('length');
34
        $searchPhrase                = $this->request->getPost('search');
35
        $this->view->draw            = $currentPage;
36
        $this->view->recordsTotal    = 0;
37
        $this->view->recordsFiltered = 0;
38
        $this->view->data            = [];
39
40
        // Посчитаем количество уникальных звонков без учета фильтров
41
        $parameters = [];
42
        $parameters['columns'] = 'COUNT(DISTINCT(linkedid)) as rows';
43
        $recordsTotalReq       = CallDetailRecords::findFirst($parameters);
44
        if ($recordsTotalReq) {
45
            $recordsTotal             = $recordsTotalReq->rows;
46
            $this->view->recordsTotal = $recordsTotal;
47
        } else {
48
            return;
49
        }
50
        // Посчитаем количество уникальных звонков с учетом фильтров
51
        if ( ! empty($searchPhrase['value'])) {
52
            $this->prepareConditionsForSearchPhrases($searchPhrase['value'], $parameters);
53
            // Если мы не смогли расшифровать строку запроса вернем пустой результата
54
            if (empty($parameters['conditions'])) {
55
                return;
56
            }
57
        }
58
        $recordsFilteredReq = CallDetailRecords::findFirst($parameters);
59
        if ($recordsFilteredReq) {
60
            $recordsFiltered             = $recordsFilteredReq->rows;
61
            $this->view->recordsFiltered = $recordsFiltered;
62
        }
63
64
        // Найдем все LinkedID подходящих под заданный фильтр
65
        $parameters['columns'] = 'DISTINCT(linkedid) as linkedid';
66
        $parameters['order']   = ['start desc'];
67
        $parameters['limit']   = $recordsPerPage;
68
        $parameters['offset']  = $position;
69
70
        $selectedLinkedIds = CallDetailRecords::find($parameters);
71
        $arrIDS            = [];
72
        foreach ($selectedLinkedIds as $item) {
73
            $arrIDS[] = $item->linkedid;
74
        }
75
76
        if (count($arrIDS) === 0) {
77
            return;
78
        }
79
80
        // Получим все детальные записи для обработки и склеивания
81
        if (count($arrIDS) === 1) {
82
            $parameters = [
83
                'conditions' => 'linkedid = :ids:',
84
                'columns'    => 'id, disposition, start, src_num, dst_num, billsec, recordingfile, did, dst_chan, linkedid, is_app',
85
                'bind'       => [
86
                    'ids' => $arrIDS[0],
87
                ],
88
                'order'      => ['linkedid desc', 'start asc'],
89
            ];
90
        } else {
91
            $parameters = [
92
                'conditions' => 'linkedid IN ({ids:array})',
93
                'columns'    => 'id, disposition, start, src_num, dst_num, billsec, recordingfile, did, dst_chan, linkedid, is_app',
94
                'bind'       => [
95
                    'ids' => $arrIDS,
96
                ],
97
                'order'      => ['linkedid desc', 'start asc'],
98
            ];
99
        }
100
101
        $selectedRecords = CallDetailRecords::find($parameters);
102
103
        $arrCdr = [];
104
105
        $objectLinkedCallRecord = (object)[
106
            'linkedid'    => '',
107
            'disposition' => '',
108
            'start'       => '',
109
            'src_num'     => '',
110
            'dst_num'     => '',
111
            'billsec'     => 0,
112
            'answered'    => [],
113
            'detail'      => [],
114
        ];
115
116
        foreach ($selectedRecords as $record) {
117
            if ( ! array_key_exists($record->linkedid, $arrCdr)) {
118
                $arrCdr[$record->linkedid] = clone $objectLinkedCallRecord;
119
            }
120
            if ($record->is_app !== '1'
121
                && $record->billsec > 0
122
                && ($record->disposition === 'ANSWER' || $record->disposition === 'ANSWERED')) {
123
                $disposition = 'ANSWERED';
124
            } else {
125
                $disposition = 'NOANSWER';
126
            }
127
            $linkedRecord              = $arrCdr[$record->linkedid];
128
            $linkedRecord->linkedid    = $record->linkedid;
129
            $linkedRecord->disposition = $linkedRecord->disposition !== 'ANSWERED' ? $disposition : 'ANSWERED';
130
            $linkedRecord->start       = $linkedRecord->start === '' ? $record->start : $linkedRecord->start;
131
            $linkedRecord->src_num     = $linkedRecord->src_num === '' ? $record->src_num : $linkedRecord->src_num;
132
            if ( ! empty($record->did)) {
133
                $linkedRecord->dst_num = $record->did;
134
            } else {
135
                $linkedRecord->dst_num = $linkedRecord->dst_num === '' ? $record->dst_num : $linkedRecord->dst_num;
136
            }
137
            $linkedRecord->billsec += (int)$record->billsec;
138
            if ($disposition === 'ANSWERED') {
139
                $linkedRecord->answered[] = [
140
                    'id'            => $record->id,
141
                    'src_num'       => $record->src_num,
142
                    'dst_num'       => $record->dst_num,
143
                    'recordingfile' => $record->recordingfile,
144
                ];
145
            }
146
            $linkedRecord->detail[] = $record;
147
        }
148
        $output = [];
149
        foreach ($arrCdr as $cdr) {
150
            $timing   = gmdate($cdr->billsec < 3600 ? 'i:s' : 'G:i:s', $cdr->billsec);
151
            $output[] = [
152
                date('d-m-Y H:i:s', strtotime($cdr->start)),
153
                $cdr->src_num,
154
                $cdr->dst_num,
155
                $timing === '00:00' ? '' : $timing,
156
                $cdr->answered,
157
                $cdr->disposition,
158
                'DT_RowId'    => $cdr->linkedid,
159
                'DT_RowClass' => 'NOANSWER' === $cdr->disposition ? 'ui negative' : 'detailed',
160
            ];
161
        }
162
163
        $this->view->data = $output;
164
    }
165
166
    /**
167
     *
168
     * Подготовка параметров запроса для фильтрации CDR записей
169
     *
170
     * @param string $searchPhrase поисковая фраза, которую ввел пользователь
171
     * @param array $parameters   параметры запроса CDR
172
     */
173
    private function prepareConditionsForSearchPhrases(string &$searchPhrase, array &$parameters): void
174
    {
175
        $parameters['conditions'] = '';
176
177
        // Поищем линкдиды, и если они там есть, то игнориуем все предыдущие параметры запроса
178
        if (preg_match_all("/mikopbx-\d+.\d+/", $searchPhrase, $matches) && count($matches[0]) === 1) {
179
            $parameters['conditions']           = 'linkedid = :SearchPhrase:';
180
            $parameters['bind']['SearchPhrase'] = $matches[0][0];
181
182
            return;
183
        }
184
185
        // Поищем даты
186
        if (preg_match_all("/\d{2}\/\d{2}\/\d{4}/", $searchPhrase, $matches)) {
187
            if (count($matches[0]) === 1) {
188
                $date                                  = DateTime::createFromFormat('d/m/Y', $matches[0][0]);
189
                $requestedDate                         = $date->format('Y-m-d');
190
                $tomorrowDate                          = $date->modify('+1 day')->format('Y-m-d');
191
                $parameters['conditions']              .= 'start BETWEEN :dateFromPhrase1: AND :dateFromPhrase2:';
192
                $parameters['bind']['dateFromPhrase1'] = $requestedDate;
193
                $parameters['bind']['dateFromPhrase2'] = $tomorrowDate;
194
                $searchPhrase                          = str_replace($matches[0][0], "", $searchPhrase);
195
            } elseif (count($matches[0]) === 2) {
196
                $parameters['conditions']              .= 'start BETWEEN :dateFromPhrase1: AND :dateFromPhrase2:';
197
                $date                                  = DateTime::createFromFormat('d/m/Y', $matches[0][0]);
198
                $requestedDate                         = $date->format('Y-m-d');
199
                $parameters['bind']['dateFromPhrase1'] = $requestedDate;
200
                $date                                  = DateTime::createFromFormat('d/m/Y', $matches[0][1]);
201
                $tomorrowDate                          = $date->modify('+1 day')->format('Y-m-d');
202
                $parameters['bind']['dateFromPhrase2'] = $tomorrowDate;
203
                $searchPhrase                          = str_replace(
204
                    [$matches[0][0], $matches[0][1]],
205
                    '',
206
                    $searchPhrase
207
                );
208
            }
209
        }
210
211
        // Поищем номера телефонов
212
        $searchPhrase = str_replace(['(', ')', '-', '+'], '', $searchPhrase);
213
214
        if (preg_match_all("/\d+/", $searchPhrase, $matches)) {
215
            $needCloseAnd     = false;
216
            $extensionsLength = PbxSettings::getValueByKey('PBXInternalExtensionLength');
217
            if ($parameters['conditions'] !== '') {
218
                $parameters['conditions'] .= ' AND (';
219
                $needCloseAnd             = true;
220
            }
221
            if (count($matches[0]) === 1) {
222
                if ($extensionsLength === strlen($matches[0][0])) {
223
                    $parameters['conditions']            .= 'src_num = :SearchPhrase1: OR dst_num = :SearchPhrase2:';
224
                    $parameters['bind']['SearchPhrase1'] = $matches[0][0];
225
                    $parameters['bind']['SearchPhrase2'] = $matches[0][0];
226
                } else {
227
                    $seekNumber                          = substr($matches[0][0], -9);
228
                    $parameters['conditions']            .= 'src_num LIKE :SearchPhrase1: OR dst_num LIKE :SearchPhrase2: OR did LIKE :SearchPhrase3:';
229
                    $parameters['bind']['SearchPhrase1'] = "%{$seekNumber}%";
230
                    $parameters['bind']['SearchPhrase2'] = "%{$seekNumber}%";
231
                    $parameters['bind']['SearchPhrase3'] = "%{$seekNumber}%";
232
                }
233
234
                $searchPhrase = str_replace($matches[0][0], '', $searchPhrase);
235
            } elseif (count($matches[0]) === 2) {
236
                if ($extensionsLength === strlen($matches[0][0]) && $extensionsLength === strlen($matches[0][1])) {
237
                    $parameters['conditions']            .= '(src_num = :SearchPhrase1: AND dst_num = :SearchPhrase2:)';
238
                    $parameters['conditions']            .= ' OR (src_num = :SearchPhrase3: AND dst_num = :SearchPhrase4:)';
239
                    $parameters['conditions']            .= ' OR (src_num = :SearchPhrase5: AND did = :SearchPhrase6:)';
240
                    $parameters['conditions']            .= ' OR (src_num = :SearchPhrase8: AND did = :SearchPhrase7:)';
241
                    $parameters['bind']['SearchPhrase1'] = $matches[0][0];
242
                    $parameters['bind']['SearchPhrase2'] = $matches[0][1];
243
                    $parameters['bind']['SearchPhrase3'] = $matches[0][1];
244
                    $parameters['bind']['SearchPhrase4'] = $matches[0][0];
245
                    $parameters['bind']['SearchPhrase5'] = $matches[0][1];
246
                    $parameters['bind']['SearchPhrase6'] = $matches[0][0];
247
                    $parameters['bind']['SearchPhrase7'] = $matches[0][1];
248
                    $parameters['bind']['SearchPhrase8'] = $matches[0][0];
249
                } elseif ($extensionsLength === strlen($matches[0][0]) && $extensionsLength !== strlen(
250
                        $matches[0][1]
251
                    )) {
252
                    $seekNumber                          = substr($matches[0][1], -9);
253
                    $parameters['conditions']            .= '(src_num = :SearchPhrase1: AND dst_num LIKE :SearchPhrase2:)';
254
                    $parameters['conditions']            .= ' OR (src_num LIKE :SearchPhrase3: AND dst_num = :SearchPhrase4:)';
255
                    $parameters['conditions']            .= ' OR (src_num LIKE :SearchPhrase5: AND did = :SearchPhrase6:)';
256
                    $parameters['conditions']            .= ' OR (src_num = :SearchPhrase8: AND did LIKE :SearchPhrase7:)';
257
                    $parameters['bind']['SearchPhrase1'] = $matches[0][0];
258
                    $parameters['bind']['SearchPhrase2'] = "%{$seekNumber}%";
259
                    $parameters['bind']['SearchPhrase3'] = "%{$seekNumber}%";
260
                    $parameters['bind']['SearchPhrase4'] = $matches[0][0];
261
                    $parameters['bind']['SearchPhrase5'] = "%{$seekNumber}%";
262
                    $parameters['bind']['SearchPhrase6'] = $matches[0][0];
263
                    $parameters['bind']['SearchPhrase7'] = "%{$seekNumber}%";
264
                    $parameters['bind']['SearchPhrase8'] = $matches[0][0];
265
                } elseif ($extensionsLength !== strlen($matches[0][0]) && $extensionsLength === strlen(
266
                        $matches[0][1]
267
                    )) {
268
                    $seekNumber                          = substr($matches[0][0], -9);
269
                    $parameters['conditions']            .= '(src_num LIKE :SearchPhrase1: AND dst_num = :SearchPhrase2:)';
270
                    $parameters['conditions']            .= ' OR (src_num = :SearchPhrase3: AND dst_num LIKE :SearchPhrase4:)';
271
                    $parameters['conditions']            .= ' OR (src_num LIKE :SearchPhrase5: AND did = :SearchPhrase6:)';
272
                    $parameters['conditions']            .= ' OR (src_num = :SearchPhrase8: AND did LIKE :SearchPhrase7:)';
273
                    $parameters['bind']['SearchPhrase1'] = "%{$seekNumber}%";
274
                    $parameters['bind']['SearchPhrase2'] = $matches[0][1];
275
                    $parameters['bind']['SearchPhrase3'] = $matches[0][1];
276
                    $parameters['bind']['SearchPhrase4'] = "%{$seekNumber}%";
277
                    $parameters['bind']['SearchPhrase5'] = "%{$seekNumber}%";
278
                    $parameters['bind']['SearchPhrase6'] = $matches[0][1];
279
                    $parameters['bind']['SearchPhrase7'] = "%{$seekNumber}%";
280
                    $parameters['bind']['SearchPhrase8'] = $matches[0][1];
281
                } else {
282
                    $seekNumber0                         = substr($matches[0][0], -9);
283
                    $seekNumber1                         = substr($matches[0][1], -9);
284
                    $parameters['conditions']            .= '(src_num LIKE :SearchPhrase1: AND dst_num LIKE :SearchPhrase2:)';
285
                    $parameters['conditions']            .= ' OR (src_num LIKE :SearchPhrase3: AND dst_num LIKE :SearchPhrase4:)';
286
                    $parameters['conditions']            .= ' OR (src_num LIKE :SearchPhrase5: AND did LIKE :SearchPhrase6:)';
287
                    $parameters['conditions']            .= ' OR (src_num LIKE :SearchPhrase7: AND did LIKE :SearchPhrase8:)';
288
                    $parameters['bind']['SearchPhrase1'] = "%{$seekNumber0}%";
289
                    $parameters['bind']['SearchPhrase2'] = "%{$seekNumber1}%";
290
                    $parameters['bind']['SearchPhrase3'] = "%{$seekNumber1}%";
291
                    $parameters['bind']['SearchPhrase4'] = "%{$seekNumber0}%";
292
                    $parameters['bind']['SearchPhrase5'] = "%{$seekNumber0}%";
293
                    $parameters['bind']['SearchPhrase6'] = "%{$seekNumber1}%";
294
                    $parameters['bind']['SearchPhrase7'] = "%{$seekNumber1}%";
295
                    $parameters['bind']['SearchPhrase8'] = "%{$seekNumber0}%";
296
                }
297
                $searchPhrase = str_replace([$matches[0][0], $matches[0][1]], '', $searchPhrase);
298
            }
299
            if ($needCloseAnd) {
300
                $parameters['conditions'] .= ')';
301
            }
302
        }
303
    }
304
}