| Total Complexity | 55 |
| Total Lines | 286 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Complex classes like IncomingContexts 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.
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 IncomingContexts, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 14 | class IncomingContexts extends ConfigClass{ |
||
| 15 | /** |
||
| 16 | * Генератор входящих контекстов. |
||
| 17 | * |
||
| 18 | * @param string | array $provider |
||
| 19 | * @param string | array $login |
||
| 20 | * @param string $uniqid |
||
| 21 | * |
||
| 22 | * @return string |
||
| 23 | */ |
||
| 24 | public static function generate($provider, $login = '', $uniqid = ''): string |
||
| 25 | { |
||
| 26 | $conf = ''; |
||
| 27 | $dialplan = []; |
||
| 28 | $di = Di::getDefault(); |
||
| 29 | if ($di === null) { |
||
| 30 | return ''; |
||
| 31 | } |
||
| 32 | $additionalModules = $di->getShared(PBXConfModulesProvider::SERVICE_NAME); |
||
| 33 | $confExtensions = ConferenceConf::getConferenceExtensions(); |
||
| 34 | |||
| 35 | $filter = self::getRoutesFilter($provider); |
||
| 36 | |||
| 37 | /** @var IncomingRoutingTable $default_action */ |
||
| 38 | $default_action = IncomingRoutingTable::findFirst('priority = 9999'); |
||
| 39 | /** @var IncomingRoutingTable $m_data */ |
||
| 40 | $m_data = IncomingRoutingTable::find($filter); |
||
| 41 | $data = $m_data->toArray(); |
||
| 42 | uasort($data, __CLASS__ . '::sortArrayByPriority'); |
||
| 43 | |||
| 44 | $need_def_rout = self::checkNeedDefRout($provider, $data); |
||
| 45 | $config = new MikoPBXConfig(); |
||
| 46 | $lang = str_replace('_', '-', $config->getGeneralSettings('PBXLanguage')); |
||
| 47 | |||
| 48 | $rout_data_dial = []; |
||
| 49 | foreach ($data as $rout) { |
||
| 50 | $number = trim($rout['number']); |
||
| 51 | $timeout = trim($rout['timeout']); |
||
| 52 | $rout_number = ($number === '') ? 'X!' : $number; |
||
| 53 | $rout_data = &$dialplan[$rout_number]; |
||
| 54 | self::generateRouteDialplan($rout_data, $provider, $rout, $lang, $additionalModules); |
||
| 55 | self::generateDialActions($rout_data_dial, $rout, $rout_number, $confExtensions, $timeout, $provider, $number); |
||
| 56 | } |
||
| 57 | |||
| 58 | self::multiplyExtensionsInDialplan($dialplan, $rout_data_dial, $login, $data, $need_def_rout, $provider); |
||
| 59 | |||
| 60 | self::trimDialplans($dialplan, $rout_data_dial); |
||
| 61 | |||
| 62 | self::createSummaryDialplan($conf, $provider, $uniqid, $dialplan, $default_action, $confExtensions, $additionalModules); |
||
| 63 | |||
| 64 | return $conf; |
||
| 65 | } |
||
| 66 | |||
| 67 | /** |
||
| 68 | * @param array|string $provider |
||
| 69 | * @return array|string[] |
||
| 70 | */ |
||
| 71 | private static function getRoutesFilter($provider): array{ |
||
| 72 | if ('none' === $provider) { |
||
| 73 | // Звонки по sip uri. |
||
| 74 | $filter = ['provider IS NULL AND priority<>9999', 'order' => 'provider,priority,extension',]; |
||
| 75 | } elseif (is_array($provider)) { |
||
| 76 | $filter = ['provider IN ({provider:array})', 'bind' => ['provider' => array_keys($provider),], 'order' => 'provider,priority,extension',]; |
||
| 77 | } else { |
||
| 78 | // Звонки через провайдера. |
||
| 79 | $filter = ["provider = '$provider'", 'order' => 'provider,priority,extension',]; |
||
| 80 | } |
||
| 81 | return $filter; |
||
| 82 | } |
||
| 83 | |||
| 84 | /** |
||
| 85 | * Проверка нужен ли дефолтный маршрут для провайдера. |
||
| 86 | * @param $provider |
||
| 87 | * @param array $data |
||
| 88 | * @return bool |
||
| 89 | */ |
||
| 90 | private static function checkNeedDefRout($provider, array &$data): bool{ |
||
| 91 | $need_def_rout = true; |
||
| 92 | foreach ($data as $rout) { |
||
| 93 | $number = trim($rout['number']); |
||
| 94 | if ($number === 'X!' || $number === '') { |
||
| 95 | $need_def_rout = false; |
||
| 96 | break; |
||
| 97 | } |
||
| 98 | } |
||
| 99 | if ($need_def_rout === true && 'none' !== $provider) { |
||
| 100 | $data[] = ['number' => '', 'extension' => '', 'timeout' => '']; |
||
| 101 | } |
||
| 102 | return $need_def_rout; |
||
| 103 | } |
||
| 104 | |||
| 105 | /** |
||
| 106 | * @param $rout_data |
||
| 107 | * @param $provider |
||
| 108 | * @param array $rout |
||
| 109 | * @param string $lang |
||
| 110 | * @param $additionalModules |
||
| 111 | */ |
||
| 112 | private static function generateRouteDialplan(?string &$rout_data, $provider, array $rout, string $lang, $additionalModules): void{ |
||
| 113 | if (!empty($rout_data)) { |
||
| 114 | return; |
||
| 115 | } |
||
| 116 | $number = trim($rout['number']); |
||
| 117 | $rout_number = ($number === '') ? 'X!' : $number; |
||
| 118 | |||
| 119 | $ext_prefix = ('none' === $provider) ? '' : '_'; |
||
| 120 | $rout_data .= "exten => {$ext_prefix}{$rout_number},1,NoOp(--- Incoming call ---)\n\t"; |
||
| 121 | $rout_data .= 'same => n,Set(CHANNEL(language)=' . $lang . ')' . "\n\t"; |
||
| 122 | $rout_data .= 'same => n,Set(CHANNEL(hangup_handler_wipe)=hangup_handler,s,1)' . "\n\t"; |
||
| 123 | $rout_data .= 'same => n,Set(__FROM_DID=${EXTEN})' . "\n\t"; |
||
| 124 | $rout_data .= 'same => n,Set(__FROM_CHAN=${CHANNEL})' . "\n\t"; |
||
| 125 | // Установка имени пира. |
||
| 126 | $rout_data .= 'same => n,ExecIf($["${CHANNEL(channeltype)}" != "Local"]?Gosub(set_from_peer,s,1))' . "\n\t"; |
||
| 127 | $rout_data .= 'same => n,ExecIf($["${CHANNEL(channeltype)}" == "Local"]?Set(__FROM_PEER=${CALLERID(num)}))' . "\n\t"; |
||
| 128 | $rout_data .= 'same => n,Gosub(add-trim-prefix-clid,${EXTEN},1)' . "\n\t"; |
||
| 129 | |||
| 130 | foreach ($additionalModules as $appClass) { |
||
| 131 | $addition = $appClass->generateIncomingRoutBeforeDial($rout_number); |
||
| 132 | if (!empty($addition)) { |
||
| 133 | $rout_data .= $appClass->confBlockWithComments($addition); |
||
| 134 | } |
||
| 135 | } |
||
| 136 | // Описываем возможность прыжка в пользовательский sub контекст. |
||
| 137 | $rout_data .= " \n\t" . 'same => n,GosubIf($["${DIALPLAN_EXISTS(${CONTEXT}-custom,${EXTEN},1)}" == "1"]?${CONTEXT}-custom,${EXTEN},1)'; |
||
| 138 | |||
| 139 | if (!empty($rout['extension'])) { |
||
| 140 | $rout_data = rtrim($rout_data); |
||
| 141 | } |
||
| 142 | } |
||
| 143 | |||
| 144 | /** |
||
| 145 | * @param array $rout_data_dial |
||
| 146 | * @param $rout |
||
| 147 | * @param string $rout_number |
||
| 148 | * @param array $confExtensions |
||
| 149 | * @param string $timeout |
||
| 150 | * @param $provider |
||
| 151 | * @param string $number |
||
| 152 | * @return void |
||
| 153 | */ |
||
| 154 | private static function generateDialActions(array &$rout_data_dial, $rout, string $rout_number, array $confExtensions, string $timeout, $provider, string $number): void{ |
||
| 155 | if (empty($rout['extension'])) { |
||
| 156 | return; |
||
| 157 | } |
||
| 158 | // Обязательно проверяем "DIALSTATUS", в случае с парковой через AMI вызова это необходимо. |
||
| 159 | // При ответе может отработать следующий приоритет. |
||
| 160 | if (!isset($rout_data_dial[$rout_number])) { |
||
| 161 | $rout_data_dial[$rout_number] = ''; |
||
| 162 | } |
||
| 163 | |||
| 164 | if (in_array($rout['extension'], $confExtensions, true)) { |
||
| 165 | // Это конференция. Тут не требуется обработка таймаута ответа. |
||
| 166 | // Вызов будет отвечен сразу конференцией. |
||
| 167 | $dial_command = " \n\t" . 'same => n,' . 'ExecIf($["${M_DIALSTATUS}" != "ANSWER"]?' . "Goto(internal,{$rout['extension']},1));"; |
||
| 168 | $rout_data_dial[$rout_number] .= ""; |
||
| 169 | } else { |
||
| 170 | $dial_command = " \n\t" . 'same => n,' . 'ExecIf($["${M_DIALSTATUS}" != "ANSWER"]?' . "Dial(Local/{$rout['extension']}@internal-incoming/n,{$timeout},TKg));"; |
||
| 171 | $rout_data_dial[$rout_number] .= " \n\t" . "same => n,Set(M_TIMEOUT={$timeout})"; |
||
| 172 | } |
||
| 173 | $rout_data_dial[$rout_number] .= $dial_command; |
||
| 174 | |||
| 175 | if (!is_array($provider)) { |
||
| 176 | return; |
||
| 177 | } |
||
| 178 | |||
| 179 | $key = $provider[$rout['provider']] ?? ''; |
||
| 180 | if (!isset($rout_data_dial[$key])) { |
||
| 181 | $rout_data_dial[$key] = ''; |
||
| 182 | } |
||
| 183 | if (empty($number)) { |
||
| 184 | $rout_data_dial[$key] .= $dial_command; |
||
| 185 | } |
||
| 186 | } |
||
| 187 | |||
| 188 | /** |
||
| 189 | * @param array $dialplans |
||
| 190 | * @param array $rout_data_dial |
||
| 191 | */ |
||
| 192 | private static function trimDialplans(array $dialplans, array $rout_data_dial):void{ |
||
| 193 | foreach ($dialplans as $key => &$dialplan) { |
||
| 194 | if (!array_key_exists($key, $rout_data_dial)) { |
||
| 195 | continue; |
||
| 196 | } |
||
| 197 | $dialplan = rtrim($dialplan); |
||
| 198 | $dialplan .= $rout_data_dial[$key]; |
||
| 199 | } |
||
| 200 | } |
||
| 201 | |||
| 202 | |||
| 203 | /** |
||
| 204 | * Добавление дополнительных exten в Dialplan |
||
| 205 | * @param array $dialplan |
||
| 206 | * @param array $rout_data_dial |
||
| 207 | * @param $login |
||
| 208 | * @param array $data |
||
| 209 | * @param bool $need_def_rout |
||
| 210 | * @param $provider |
||
| 211 | */ |
||
| 212 | private static function multiplyExtensionsInDialplan(array &$dialplan, array &$rout_data_dial, $login, array $data, bool $need_def_rout, $provider): void{ |
||
| 213 | if (is_string($login)) { |
||
| 214 | $add_login_pattern = self::needAddLoginExtension($login, $data); |
||
| 215 | if ($add_login_pattern && array_key_exists('X!', $rout_data_dial) && isset($dialplan['X!'])) { |
||
| 216 | $dialplan[$login] = str_replace('_X!,1', "{$login},1", $dialplan['X!']); |
||
| 217 | $rout_data_dial[$login] = $rout_data_dial['X!']; |
||
| 218 | } elseif ($add_login_pattern === true && $need_def_rout === true && count($data) === 1) { |
||
| 219 | // Только маршрут "По умолчанию". |
||
| 220 | $dialplan[$login] = str_replace('_X!,1', "{$login},1", $dialplan['X!']); |
||
| 221 | } |
||
| 222 | } elseif (is_array($provider)) { |
||
| 223 | foreach (array_values($provider) as $_login) { |
||
| 224 | $dialplan[$_login] = str_replace('_X!,1', "{$_login},1", $dialplan['X!']); |
||
| 225 | } |
||
| 226 | } |
||
| 227 | } |
||
| 228 | |||
| 229 | /** |
||
| 230 | * Если логин не числовой, то нужно добавить такой Exten. |
||
| 231 | * @param string $login |
||
| 232 | * @param array $data |
||
| 233 | * @return bool |
||
| 234 | */ |
||
| 235 | private static function needAddLoginExtension(string $login, array $data): bool{ |
||
| 256 | } |
||
| 257 | |||
| 258 | /** |
||
| 259 | * @param string $conf |
||
| 260 | * @param $provider |
||
| 261 | * @param string $uniqId |
||
| 262 | * @param array $dialplan |
||
| 263 | * @param IncomingRoutingTable $default_action |
||
| 264 | * @param array $confExtensions |
||
| 265 | * @param $additionalModules |
||
| 266 | * @return string |
||
| 267 | */ |
||
| 268 | private static function createSummaryDialplan(string & $conf, $provider, string $uniqId, array $dialplan, IncomingRoutingTable $default_action, array $confExtensions, $additionalModules): string{ |
||
| 300 | } |
||
| 301 | |||
| 302 | } |