| Total Complexity | 57 | 
| Total Lines | 310 | 
| Duplicated Lines | 0 % | 
| Changes | 2 | ||
| 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 |             if (empty($rout_data)) { | 
            ||
| 55 | self::generateRouteDialplan($rout_data, $provider, $rout, $lang, $additionalModules);  | 
            ||
| 56 | }  | 
            ||
| 57 | self::generateDialActions($rout_data_dial, $rout, $rout_number, $confExtensions, $timeout, $provider, $number);  | 
            ||
| 58 | }  | 
            ||
| 59 | |||
| 60 | self::multiplyExtensionsInDialplan($dialplan, $rout_data_dial, $login, $data, $need_def_rout, $provider);  | 
            ||
| 61 | self::trimDialplans($dialplan, $rout_data_dial);  | 
            ||
| 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{ | 
            ||
| 82 | }  | 
            ||
| 83 | |||
| 84 | /**  | 
            ||
| 85 | * Проверка нужен ли дефолтный маршрут для провайдера.  | 
            ||
| 86 | * @param $provider  | 
            ||
| 87 | * @param array $data  | 
            ||
| 88 | * @return bool  | 
            ||
| 89 | */  | 
            ||
| 90 |     private static function checkNeedDefRout($provider, array &$data): bool{ | 
            ||
| 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 | |||
| 114 | $number = trim($rout['number']);  | 
            ||
| 115 | $rout_number = ($number === '') ? 'X!' : $number;  | 
            ||
| 116 | |||
| 117 |         $ext_prefix = ('none' === $provider) ? '' : '_'; | 
            ||
| 118 |         $rout_data .= "exten => {$ext_prefix}{$rout_number},1,NoOp(--- Incoming call ---)\n\t"; | 
            ||
| 119 | $rout_data .= 'same => n,Set(CHANNEL(language)=' . $lang . ')' . "\n\t";  | 
            ||
| 120 | $rout_data .= 'same => n,Set(CHANNEL(hangup_handler_wipe)=hangup_handler,s,1)' . "\n\t";  | 
            ||
| 121 |         $rout_data .= 'same => n,Set(__FROM_DID=${EXTEN})' . "\n\t"; | 
            ||
| 122 |         $rout_data .= 'same => n,Set(__FROM_CHAN=${CHANNEL})' . "\n\t"; | 
            ||
| 123 | // Установка имени пира.  | 
            ||
| 124 |         $rout_data .= 'same => n,ExecIf($["${CHANNEL(channeltype)}" != "Local"]?Gosub(set_from_peer,s,1))' . "\n\t"; | 
            ||
| 125 |         $rout_data .= 'same => n,ExecIf($["${CHANNEL(channeltype)}" == "Local"]?Set(__FROM_PEER=${CALLERID(num)}))' . "\n\t"; | 
            ||
| 126 |         $rout_data .= 'same => n,Gosub(add-trim-prefix-clid,${EXTEN},1)' . "\n\t"; | 
            ||
| 127 | |||
| 128 |         foreach ($additionalModules as $appClass) { | 
            ||
| 129 | $addition = $appClass->generateIncomingRoutBeforeDial($rout_number);  | 
            ||
| 130 |             if (!empty($addition)) { | 
            ||
| 131 | $rout_data .= $appClass->confBlockWithComments($addition);  | 
            ||
| 132 | }  | 
            ||
| 133 | }  | 
            ||
| 134 | // Описываем возможность прыжка в пользовательский sub контекст.  | 
            ||
| 135 |         $rout_data .= " \n\t" . 'same => n,GosubIf($["${DIALPLAN_EXISTS(${CONTEXT}-custom,${EXTEN},1)}" == "1"]?${CONTEXT}-custom,${EXTEN},1)'; | 
            ||
| 136 | |||
| 137 |         if (!empty($rout['extension'])) { | 
            ||
| 138 | $rout_data = rtrim($rout_data);  | 
            ||
| 139 | }  | 
            ||
| 140 | }  | 
            ||
| 141 | |||
| 142 | /**  | 
            ||
| 143 | * @param array $rout_data_dial  | 
            ||
| 144 | * @param $rout  | 
            ||
| 145 | * @param string $rout_number  | 
            ||
| 146 | * @param array $confExtensions  | 
            ||
| 147 | * @param string $timeout  | 
            ||
| 148 | * @param $provider  | 
            ||
| 149 | * @param string $number  | 
            ||
| 150 | * @return void  | 
            ||
| 151 | */  | 
            ||
| 152 |     private static function generateDialActions(array &$rout_data_dial, $rout, string $rout_number, array $confExtensions, string $timeout, $provider, string $number): void{ | 
            ||
| 153 |         if (empty($rout['extension'])) { | 
            ||
| 154 | return;  | 
            ||
| 155 | }  | 
            ||
| 156 | // Обязательно проверяем "DIALSTATUS", в случае с парковой через AMI вызова это необходимо.  | 
            ||
| 157 | // При ответе может отработать следующий приоритет.  | 
            ||
| 158 |         if (!isset($rout_data_dial[$rout_number])) { | 
            ||
| 159 | $rout_data_dial[$rout_number] = '';  | 
            ||
| 160 | }  | 
            ||
| 161 | |||
| 162 |         if (in_array($rout['extension'], $confExtensions, true)) { | 
            ||
| 163 | // Это конференция. Тут не требуется обработка таймаута ответа.  | 
            ||
| 164 | // Вызов будет отвечен сразу конференцией.  | 
            ||
| 165 |             $dial_command = " \n\t" . 'same => n,' . 'ExecIf($["${M_DIALSTATUS}" != "ANSWER"]?' . "Goto(internal,{$rout['extension']},1));"; | 
            ||
| 166 | $rout_data_dial[$rout_number] .= "";  | 
            ||
| 167 |         } else { | 
            ||
| 168 |             $dial_command = " \n\t" . 'same => n,' . 'ExecIf($["${M_DIALSTATUS}" != "ANSWER"]?' . "Dial(Local/{$rout['extension']}@internal-incoming/n,{$timeout},TKg));"; | 
            ||
| 169 |             $rout_data_dial[$rout_number] .= " \n\t" . "same => n,Set(M_TIMEOUT={$timeout})"; | 
            ||
| 170 | }  | 
            ||
| 171 | $rout_data_dial[$rout_number] .= $dial_command;  | 
            ||
| 172 | |||
| 173 |         if (!is_array($provider)) { | 
            ||
| 174 | return;  | 
            ||
| 175 | }  | 
            ||
| 176 | |||
| 177 | $key = $provider[$rout['provider']] ?? '';  | 
            ||
| 178 |         if (!isset($rout_data_dial[$key])) { | 
            ||
| 179 | $rout_data_dial[$key] = '';  | 
            ||
| 180 | }  | 
            ||
| 181 |         if (empty($number)) { | 
            ||
| 182 | $rout_data_dial[$key] .= $dial_command;  | 
            ||
| 183 | }  | 
            ||
| 184 | }  | 
            ||
| 185 | |||
| 186 | /**  | 
            ||
| 187 | * @param array $dialplans  | 
            ||
| 188 | * @param array $rout_data_dial  | 
            ||
| 189 | */  | 
            ||
| 190 |     private static function trimDialplans(array $dialplans, array $rout_data_dial):void{ | 
            ||
| 191 |         foreach ($dialplans as $key => &$dialplan) { | 
            ||
| 192 |             if (!array_key_exists($key, $rout_data_dial)) { | 
            ||
| 193 | continue;  | 
            ||
| 194 | }  | 
            ||
| 195 | $dialplan = rtrim($dialplan);  | 
            ||
| 196 | $dialplan .= $rout_data_dial[$key];  | 
            ||
| 197 | }  | 
            ||
| 198 | }  | 
            ||
| 199 | |||
| 200 | |||
| 201 | /**  | 
            ||
| 202 | * Добавление дополнительных exten в Dialplan  | 
            ||
| 203 | * @param array $dialplan  | 
            ||
| 204 | * @param array $rout_data_dial  | 
            ||
| 205 | * @param $login  | 
            ||
| 206 | * @param array $data  | 
            ||
| 207 | * @param bool $need_def_rout  | 
            ||
| 208 | * @param $provider  | 
            ||
| 209 | */  | 
            ||
| 210 |     private static function multiplyExtensionsInDialplan(array &$dialplan, array &$rout_data_dial, $login, array $data, bool $need_def_rout, $provider): void{ | 
            ||
| 211 |         if (is_string($login)) { | 
            ||
| 212 | self::multiplyExtensionsInDialplanStringLogin($login, $data, $rout_data_dial, $dialplan, $need_def_rout);  | 
            ||
| 213 | }  | 
            ||
| 214 |         if (is_array($provider)) { | 
            ||
| 215 |             foreach (array_values($provider) as $_login) { | 
            ||
| 216 |                 $dialplan[$_login] = str_replace('_X!,1', "{$_login},1", $dialplan['X!']); | 
            ||
| 217 | }  | 
            ||
| 218 | }  | 
            ||
| 219 | }  | 
            ||
| 220 | |||
| 221 | /**  | 
            ||
| 222 | * @param string $login  | 
            ||
| 223 | * @param array $data  | 
            ||
| 224 | * @param array $rout_data_dial  | 
            ||
| 225 | * @param array $dialplan  | 
            ||
| 226 | * @param bool $need_def_rout  | 
            ||
| 227 | */  | 
            ||
| 228 |     private static function multiplyExtensionsInDialplanStringLogin(string $login, array $data, array &$rout_data_dial, array &$dialplan, bool $need_def_rout): void{ | 
            ||
| 229 | $add_login_pattern = self::needAddLoginExtension($login, $data);  | 
            ||
| 230 |         if ($add_login_pattern && array_key_exists('X!', $rout_data_dial) && isset($dialplan['X!'])) { | 
            ||
| 231 |             $dialplan[$login] = str_replace('_X!,1', "{$login},1", $dialplan['X!']); | 
            ||
| 232 | $rout_data_dial[$login] = $rout_data_dial['X!'];  | 
            ||
| 233 |         } elseif ($add_login_pattern === true && $need_def_rout === true && count($data) === 1) { | 
            ||
| 234 | // Только маршрут "По умолчанию".  | 
            ||
| 235 |             $dialplan[$login] = str_replace('_X!,1', "{$login},1", $dialplan['X!']); | 
            ||
| 236 | }  | 
            ||
| 237 | }  | 
            ||
| 238 | |||
| 239 | /**  | 
            ||
| 240 | * Если логин не числовой, то нужно добавить такой Exten.  | 
            ||
| 241 | * @param string $login  | 
            ||
| 242 | * @param array $data  | 
            ||
| 243 | * @return bool  | 
            ||
| 244 | */  | 
            ||
| 245 |     private static function needAddLoginExtension(string $login, array $data): bool{ | 
            ||
| 266 | }  | 
            ||
| 267 | |||
| 268 | /**  | 
            ||
| 269 | * Формирование итогового dialplan.  | 
            ||
| 270 | * @param string $conf  | 
            ||
| 271 | * @param $provider  | 
            ||
| 272 | * @param string $uniqId  | 
            ||
| 273 | * @param array $dialplan  | 
            ||
| 274 | * @param IncomingRoutingTable $default_action  | 
            ||
| 275 | * @param array $confExtensions  | 
            ||
| 276 | * @param $additionalModules  | 
            ||
| 277 | * @return string  | 
            ||
| 278 | */  | 
            ||
| 279 |     private static function createSummaryDialplan(string & $conf, $provider, string $uniqId, array $dialplan, IncomingRoutingTable $default_action, array $confExtensions, $additionalModules): string{ | 
            ||
| 280 | $uniqId = is_string($provider) ? $provider : $uniqId;  | 
            ||
| 281 |         $conf .= "\n" . "[{$uniqId}-incoming]\n"; | 
            ||
| 282 |         foreach ($dialplan as $dpln) { | 
            ||
| 283 | $conf .= $dpln . "\n";  | 
            ||
| 284 |             if (null === $default_action && 'none' !== $provider) { | 
            ||
| 285 | continue;  | 
            ||
| 286 | }  | 
            ||
| 287 |             if ('extension' === $default_action->action) { | 
            ||
| 288 | $conf = self::createSummaryDialplanGoto($conf, $default_action, $confExtensions, $additionalModules, $uniqId);  | 
            ||
| 289 |                 $conf .= " \t" . 'same => n,GosubIf($["${DIALPLAN_EXISTS(${CONTEXT}-after-dial-custom,${EXTEN},1)}" == "1"]?${CONTEXT}-after-dial-custom,${EXTEN},1)' . "\n"; | 
            ||
| 290 |             } elseif ('busy' === $default_action->action) { | 
            ||
| 291 | $conf .= "\t" . "same => n,Busy()" . "\n";  | 
            ||
| 292 | }  | 
            ||
| 293 | $conf .= "\t" . "same => n,Hangup()" . "\n";  | 
            ||
| 294 | }  | 
            ||
| 295 | return $conf;  | 
            ||
| 296 | }  | 
            ||
| 297 | |||
| 298 | /**  | 
            ||
| 299 | * @param string $conf  | 
            ||
| 300 | * @param IncomingRoutingTable $default_action  | 
            ||
| 301 | * @param array $confExtensions  | 
            ||
| 302 | * @param $additionalModules  | 
            ||
| 303 | * @param string $uniqId  | 
            ||
| 304 | * @return string  | 
            ||
| 305 | */  | 
            ||
| 306 |     private static function createSummaryDialplanGoto(string $conf, IncomingRoutingTable $default_action, array $confExtensions, $additionalModules, string $uniqId): string{ | 
            ||
| 324 | }  | 
            ||
| 325 | |||
| 326 | }  |