Passed
Push — develop ( 401b81...45fd39 )
by Портнов
04:23
created

ExtensionsOutWorkTimeConf::getWorkTimeDialplan()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 17
rs 9.8666
cc 3
nc 3
nop 3
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright (C) 2017-2021 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
21
namespace MikoPBX\Core\Asterisk\Configs;
22
23
use MikoPBX\Common\Models\OutWorkTimes;
24
use MikoPBX\Common\Models\SoundFiles;
25
use MikoPBX\Core\System\Util;
26
27
class ExtensionsOutWorkTimeConf extends CoreConfigClass
28
{
29
    public const OUT_WORK_TIME_CONTEXT = 'check-out-work-time';
30
31
    /**
32
     * Генератор extensions, дополнительные контексты.
33
     * @return string
34
     */
35
    public function extensionGenContexts(): string
36
    {
37
        return $this->generateOutWorkTimes();
38
    }
39
40
    /**
41
     * Кастомизация входящего контекста для конкретного маршрута.
42
     *
43
     * @param string $rout_number
44
     *
45
     * @return string
46
     */
47
    public function generateIncomingRoutBeforeDial(string $rout_number): string
48
    {
49
        // Проверим распискние для входящих внешних звонков.
50
        return 'same => n,Gosub('.self::OUT_WORK_TIME_CONTEXT.',${EXTEN},1)'. "\n\t";
51
    }
52
53
    /**
54
     * Описываем нерабочее время.
55
     *
56
     * @return string
57
     */
58
    private function generateOutWorkTimes(): string
59
    {
60
        $conf = "\n\n[playback-exit]\n";
61
        $conf .= 'exten => '.ExtensionsConf::ALL_NUMBER_EXTENSION.',1,Gosub(dial_outworktimes,${EXTEN},1)' . "\n\t";
62
        $conf .= 'same => n,Playback(${filename})' . "\n\t";
63
        $conf .= 'same => n,Hangup()' . "\n\n";
64
65
        $conf .= 'exten => '.ExtensionsConf::DIGIT_NUMBER_EXTENSION.',1,Gosub(dial_outworktimes,${EXTEN},1)' . "\n\t";
66
        $conf .= 'same => n,Playback(${filename})' . "\n\t";
67
        $conf .= 'same => n,Hangup()' . "\n\n";
68
69
        $conf_out_set_var  = '';
70
        $checkContextsYear = [];
71
        $conf .= "[".self::OUT_WORK_TIME_CONTEXT."]\n";
72
        $conf .= $this->getWorkTimeDialplan(ExtensionsConf::ALL_NUMBER_EXTENSION,   $conf_out_set_var, $checkContextsYear);
73
        $conf .= $this->getWorkTimeDialplan(ExtensionsConf::DIGIT_NUMBER_EXTENSION, $conf_out_set_var, $checkContextsYear);
74
        $conf .= $conf_out_set_var;
75
76
        foreach ($checkContextsYear as $year => $rule){
77
            $conf .= "[".self::OUT_WORK_TIME_CONTEXT."-{$year}]\n";
78
            $conf .= 'exten => '.ExtensionsConf::ALL_NUMBER_EXTENSION.",1,NoOp(check time {$year} year)\n\t";
79
            $conf .= implode("", $rule);
80
            $conf .= "same => n,return\n\n";
81
82
            $conf .= 'exten => '.ExtensionsConf::DIGIT_NUMBER_EXTENSION.",1,NoOp(check time {$year} year)\n\t";
83
            $conf .= implode("", $rule);
84
            $conf .= "same => n,return\n\n";
85
        }
86
87
        return $conf;
88
    }
89
90
    /**
91
     * @param $extension
92
     * @param $conf_out_set_var
93
     * @param $checkContextsYear
94
     * @return string
95
     */
96
    private function getWorkTimeDialplan($extension, &$conf_out_set_var, &$checkContextsYear):string
97
    {
98
        $conf = 'exten => '.$extension.',1,Set(currentYear=${STRFTIME(,,%Y)})'."\n\t";
99
        $conf.= 'same => n,GosubIf($["${DIALPLAN_EXISTS('.self::OUT_WORK_TIME_CONTEXT.'-${currentYear},${EXTEN},1)}" == "1"]?'.self::OUT_WORK_TIME_CONTEXT.'-${currentYear},${EXTEN},1)'."\n\t";
100
        $data = OutWorkTimes::find(['order' => 'date_from']);
101
        foreach ($data as $out_data) {
102
            $intervals = $this->getOutWorkIntervals($out_data->date_from, $out_data->date_to);
103
            foreach ($intervals as $interval){
104
                $ruleData = $out_data->toArray();
105
                $ruleData['date_to']    = $interval['date_to'];
106
                $ruleData['date_from']  = $interval['date_from'];
107
                $this->generateOutWorkRule($ruleData, $conf_out_set_var, $conf, $checkContextsYear);
108
            }
109
        }
110
        $conf .= "same => n,return\n\n";
111
112
        return $conf;
113
    }
114
115
    /**
116
     * Получает массив интервалов для разных "Годов"
117
     * @param $date_from
118
     * @param $date_to
119
     * @return array
120
     */
121
    private function getOutWorkIntervals($date_from, $date_to):array{
122
        $year_from  = 1*date('Y', (int)$date_from);
123
        $year_to    = 1*date('Y', (int)$date_to);
124
125
        $intervals = [];
126
        $Year = $year_from;
127
        if($year_to === $year_from){
128
            $intervals[] = [
129
                'date_from' => $date_from,
130
                'date_to'   => $date_to
131
            ];
132
            return $intervals;
133
        }
134
        while ($Year <= $year_to){
135
            if($Year === $year_from){
136
                $intervals[] = [
137
                    'date_from' => $date_from,
138
                    'date_to'   => (string)strtotime('31-12-'.$Year)
139
                ];
140
            }elseif ($Year === $year_to){
141
                $intervals[] = [
142
                    'date_from' => (string)strtotime('01-01-'.$Year),
143
                    'date_to'   => $date_to
144
                ];
145
            }else{
146
                $intervals[] = [
147
                    'date_from' => (string)strtotime('01-01-'.$Year),
148
                    'date_to'   => (string)strtotime('31-12-'.$Year)
149
                ];
150
            }
151
            $Year++ ;
152
        }
153
        return $intervals;
154
    }
155
156
    /**
157
     * Формирование правила переключателя по времени.
158
     * @param array  $out_data
159
     * @param string $conf_out_set_var
160
     * @param string $conf
161
     * @param array  $checkContextsYear
162
     */
163
    private function generateOutWorkRule(array $out_data, string & $conf_out_set_var, string & $conf, array & $checkContextsYear):void{
164
        $year_from = '';
165
        if ( !empty($out_data['date_from']) && !empty($out_data['date_to'])) {
166
            $year_from = date('Y', (int)$out_data['date_to']);
167
        }
168
169
        $timesArray = $this->getTimesInterval($out_data);
170
        $weekdays   = $this->getWeekDayInterval($out_data);
171
172
        [$mDays,    $months]  = $this->initDaysMonthsInterval($out_data);
173
        [$appName,  $appdata] = $this->initRuleAppData($out_data, $conf_out_set_var);
174
175
        foreach ($timesArray as $times){
176
            $rule = "same => n,{$appName}($times,$weekdays,$mDays,$months?{$appdata})\n\t";
177
            if(empty($year_from)){
178
                $conf .= $rule;
179
            }else{
180
                $checkContextsYear[$year_from][] = $rule;
181
            }
182
        }
183
    }
184
185
    /**
186
     * Получает интервалы времени.
187
     * @param array $out_data
188
     * @return array
189
     */
190
    private function getTimesInterval(array $out_data): array{
191
        $time_from  = $out_data['time_from'];
192
        $time_to    = $out_data['time_to'];
193
        if (empty($time_from) && empty($time_to)) {
194
            $intervals = ['*'];
195
        } else {
196
            $time_from  = $this->normaliseTime($time_from);
197
            $time_to    = $this->normaliseTime($time_to, '23:59');
198
            if(strtotime($time_from) > strtotime($time_to)){
199
                $intervals=[
200
                    "{$time_from}-23:59",
201
                    "00:00-{$time_to}"
202
                ];
203
            }else{
204
                $intervals=[
205
                    "{$time_from}-{$time_to}"
206
                ];
207
            }
208
        }
209
        return $intervals;
210
    }
211
212
    /**
213
     * Нормализация времени в приемлемый формат.
214
     * @param        $srcTime
215
     * @param string $defVal
216
     * @return string
217
     */
218
    private function normaliseTime($srcTime, $defVal = '00:00'):string{
219
        $time = (empty($srcTime)) ? $defVal : $srcTime;
220
        return (strlen($time) === 4) ? "0{$time}" : $time;
221
    }
222
223
    /**
224
     * Устанавливает тип и данные приложения.
225
     * @param        $ruleData
226
     * @param string $conf_out_set_var
227
     * @return string[]
228
     */
229
    private function initRuleAppData($ruleData, string &$conf_out_set_var): array{
230
        if ('extension' === $ruleData['action']) {
231
            $appName = 'GotoIfTime';
232
            $appdata = "internal,{$ruleData['extension']},1";
233
        } else {
234
            /** @var SoundFiles $res */
235
            $res = SoundFiles::findFirst($ruleData['audio_message_id']);
236
            $audio_message = ($res === null) ? '' : Util::trimExtensionForFile($res->path);
237
238
            $dialplanName = "work-time-set-var-{$ruleData['id']}";
239
240
            if (strpos($conf_out_set_var, $dialplanName) === false) {
241
                $conf_out_set_var .= "[{$dialplanName}]\n" .
242
                    'exten => '.ExtensionsConf::ALL_NUMBER_EXTENSION.',1,Set(filename=' . $audio_message . ')'."\n\t" .
243
                        'same => n,Goto(playback-exit,${EXTEN},1)'."\n\n";
244
            }
245
            $appName = 'ExecIfTime';
246
            $appdata = 'Goto(' . $dialplanName . ',${EXTEN},1)';
247
        }
248
        return array($appName, $appdata);
249
    }
250
251
    /**
252
     * Возвращает диапазон дней недели.
253
     * @param array $out_data
254
     * @return string
255
     */
256
    private function getWeekDayInterval(array $out_data): string{
257
        $weekday_from = (string)$out_data['weekday_from'];
258
        $weekday_to = (string)$out_data['weekday_to'];
259
        $arr_weekday = [null, "mon", "tue", "wed", "thu", "fri", "sat", "sun"];
260
        if (empty($weekday_from) && empty($weekday_to)) {
261
            $weekdays = '*';
262
        } else {
263
            $weekday_from = (empty($weekday_from)) ? '1' : $weekday_from;
264
            $weekday_to = (empty($weekday_to)) ? '7' : $weekday_to;
265
            $weekdays = "{$arr_weekday[$weekday_from]}-{$arr_weekday[$weekday_to]}";
266
        }
267
        return $weekdays;
268
    }
269
270
    /**
271
     * Возвращает диапазон месяцев.
272
     * @param array $out_data
273
     * @return string[]
274
     */
275
    private function initDaysMonthsInterval(array $out_data): array{
276
        $date_from = $out_data['date_from'];
277
        $date_to = $out_data['date_to'];
278
        if (empty($date_from)) {
279
            $mDays = '*';
280
            $months = '*';
281
        } else {
282
            $mDays = strtolower(date("j", (int)$date_from));
283
            $months = strtolower(date("M", (int)$date_from));
284
            if (!empty($date_to)) {
285
                $mDays .= "-" . strtolower(date("j", (int)$date_to));
286
                $months .= "-" . strtolower(date("M", (int)$date_to));
287
            }
288
        }
289
        return array($mDays, $months);
290
    }
291
292
293
}