Passed
Push — develop ( debec8...47f871 )
by Nikolay
05:15
created

ModelsBase::beforeDelete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
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\Common\Models;
10
11
use MikoPBX\Core\System\Util;
12
use Phalcon\Db\Adapter\AdapterInterface;
13
use Phalcon\Db\RawValue;
14
use Phalcon\Messages\Message;
15
use Phalcon\Messages\MessageInterface;
16
use Phalcon\Mvc\Model;
17
use Phalcon\Mvc\Model\Relation;
18
use Phalcon\Mvc\Model\Resultset;
19
use Phalcon\Mvc\Model\Resultset\Simple;
20
use Phalcon\Mvc\Model\ResultsetInterface;
21
use Phalcon\Text;
22
use Phalcon\Url;
23
24
/**
25
 * @method static mixed findFirstById(array|string|int $parameters = null)
26
 * @method static mixed findFirstByKey(string|null $parameters)
27
 * @method static mixed findFirstByUniqid(array|string|int $parameters = null)
28
 * @method static mixed findFirst(array|string|int $parameters = null)
29
 * @method static ResultsetInterface find(array|string|int $parameters = null)
30
 * @method static mixed count(array $parameters = null)
31
 * @method  bool create()
32
 * @method  bool delete()
33
 * @method  bool save()
34
 * @method  bool update()
35
 * @method  array|MessageInterface[] getMessages(mixed $filter = null)
36
 * @method static AdapterInterface getReadConnection()
37
 * @method  Simple|false getRelated(string $alias, $arguments = null)
38
 */
39
abstract class ModelsBase extends Model
40
{
41
42
    public function initialize(): void
43
    {
44
        self::setup(['orm.events' => true]);
45
        $this->keepSnapshots(true);
46
47
        // Пройдемся по модулям и подключим их отношения к текущей модели, если они описаны
48
        $cacheKey   = explode('\\', static::class)[3];
49
        $modulesDir = $this->di->getConfig()->core->modulesDir;
0 ignored issues
show
Bug Best Practice introduced by
The property di does not exist on MikoPBX\Common\Models\ModelsBase. Since you implemented __get, consider adding a @property annotation.
Loading history...
50
        $parameters = [
51
            'conditions' => 'disabled=0',
52
            'cache'      => [
53
                'key'      => $cacheKey,
54
                'lifetime' => 5, //seconds
55
            ],
56
        ];
57
58
        $modules = PbxExtensionModules::find($parameters)->toArray();
59
        foreach ($modules as $module) {
60
            $moduleModelsDir = "{$modulesDir}/{$module['uniqid']}/Models";
61
            $results         = glob($moduleModelsDir . '/*.php', GLOB_NOSORT);
62
            foreach ($results as $file) {
63
                $className        = pathinfo($file)['filename'];
64
                $moduleModelClass = "\\Modules\\{$module['uniqid']}\\Models\\{$className}";
65
                if (class_exists($moduleModelClass) && method_exists($moduleModelClass, 'getDynamicRelations')) {
66
                    $moduleModelClass::getDynamicRelations($this);
67
                }
68
            }
69
        }
70
    }
71
72
    /**
73
     * Обработчик ошибок валидации, обычно сюда попадаем если неправильно
74
     * сохраняются или удаляютмя модели или неправильно настроены зависимости между ними.
75
     * Эта функция формирует список ссылок на объект который мы пытаемся удалить
76
     *
77
     * При описании отношений необходимо в foreignKey секцию добавлять атрибут
78
     * message в котором указывать алиас посе слова Models,
79
     * например Models\IvrMenuTimeout, иначе метод getRelated не сможет найти зависимые
80
     * записи в моделях
81
     */
82
    public function onValidationFails(): void
83
    {
84
        $errorMessages = $this->getMessages();
85
        if (php_sapi_name() === 'cli') {
86
            Util::sysLogMsg(__CLASS__, implode(' ', $errorMessages));
87
88
            return;
89
        }
90
        foreach ($errorMessages as $errorMessage) {
91
            if ($errorMessage->getType()==='ConstraintViolation') {
92
                    $arrMessageParts = explode('Common\\Models\\', $errorMessage->getMessage());
93
                    if (count($arrMessageParts) === 2) {
94
                        $relatedModel = $arrMessageParts[1];
95
                    } else {
96
                        $relatedModel = $errorMessage->getMessage();
97
                    }
98
                    $relatedRecords  = $this->getRelated($relatedModel);
99
                    $newErrorMessage = $this->t('ConstraintViolation');
100
                    $newErrorMessage .= "<ul class='list'>";
101
                    if ($relatedRecords === false) {
102
                        throw new Model\Exception('Error on models relationship ' . $errorMessage);
103
                    }
104
                    if ($relatedRecords instanceof Resultset) {
105
                        foreach ($relatedRecords as $item) {
106
                            $newErrorMessage .= '<li>' . $item->getRepresent(true) . '</li>';
0 ignored issues
show
Bug introduced by
The method getRepresent() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

106
                            $newErrorMessage .= '<li>' . $item->/** @scrutinizer ignore-call */ getRepresent(true) . '</li>';

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
107
                        }
108
                    } else {
109
                        $newErrorMessage .= '<li>' . $relatedRecords->getRepresent(true) . '</li>';
110
                    }
111
                    $newErrorMessage .= '</ul>';
112
                    $errorMessage->setMessage($newErrorMessage);
113
                    break;
114
            }
115
        }
116
    }
117
118
    /**
119
     * Функция для доступа к массиву переводов из моделей, используется для
120
     * сообщений на понятном пользователю языке
121
     *
122
     * @param       $message
123
     * @param array $parameters
124
     *
125
     * @return mixed
126
     */
127
    public function t($message, $parameters = [])
128
    {
129
        return $this->getDI()->getShared('translation')->t($message, $parameters);
130
    }
131
132
    /**
133
     * Fill default values from annotations
134
     */
135
    public function beforeValidationOnCreate(): void
136
    {
137
        $metaData      = $metaData = $this->di->get('modelsMetadata');
0 ignored issues
show
Bug Best Practice introduced by
The property di does not exist on MikoPBX\Common\Models\ModelsBase. Since you implemented __get, consider adding a @property annotation.
Loading history...
Unused Code introduced by
The assignment to $metaData is dead and can be removed.
Loading history...
138
        $defaultValues = $metaData->getDefaultValues($this);
139
        foreach ($defaultValues as $field => $value) {
140
            if ( ! isset($this->{$field}) || $this->{$field} === null) {
141
                $this->{$field} = new RawValue($value);
142
            }
143
        }
144
    }
145
146
    /**
147
     * Функция позволяет вывести список зависимостей с сылками,
148
     * которые мешают удалению текущей сущности
149
     *
150
     * @return bool
151
     */
152
    public function beforeDelete(): bool
153
    {
154
        return $this->checkRelationsSatisfaction($this, $this);
155
    }
156
157
    /**
158
     *  Check whether this object has unsatisfied relations or not
159
     *
160
     * @param $theFirstDeleteRecord
161
     * @param $currentDeleteRecord
162
     *
163
     * @return bool
164
     */
165
    private function checkRelationsSatisfaction($theFirstDeleteRecord, $currentDeleteRecord): bool
166
    {
167
        $result = true;
168
        $relations
169
                = $currentDeleteRecord->_modelsManager->getRelations(get_class($currentDeleteRecord));
170
        foreach ($relations as $relation) {
171
            $foreignKey = $relation->getOption('foreignKey');
172
            if ( ! array_key_exists('action', $foreignKey)) {
173
                continue;
174
            }
175
            // Проверим есть ли записи в таблице которая запрещает удаление текущих данных
176
            $relatedModel             = $relation->getReferencedModel();
177
            $mappedFields             = $relation->getFields();
178
            $mappedFields             = is_array($mappedFields)
179
                ? $mappedFields : [$mappedFields];
180
            $referencedFields         = $relation->getReferencedFields();
181
            $referencedFields         = is_array($referencedFields)
182
                ? $referencedFields : [$referencedFields];
183
            $parameters['conditions'] = '';
184
            $parameters['bind']       = [];
185
            foreach ($referencedFields as $index => $referencedField) {
186
                $parameters['conditions']             .= $index > 0
187
                    ? ' OR ' : '';
188
                $parameters['conditions']             .= $referencedField
189
                    . '= :field'
190
                    . $index . ':';
191
                $bindField
192
                                                      = $mappedFields[$index];
193
                $parameters['bind']['field' . $index] = $currentDeleteRecord->$bindField;
194
            }
195
            $relatedRecords = $relatedModel::find($parameters);
196
            switch ($foreignKey['action']) {
197
                case Relation::ACTION_RESTRICT: // Запретим удаление и выведем информацию о том какие записи запретили удалять этот элемент
198
                    foreach ($relatedRecords as $relatedRecord) {
199
                        $message = new Message(
200
                            $theFirstDeleteRecord->t(
201
                                'mo_BeforeDeleteFirst',
202
                                [
203
                                    'represent' => $relatedRecord->getRepresent(true),
204
                                ]
205
                            )
206
                        );
207
                        $theFirstDeleteRecord->appendMessage($message);
208
                        $result = false;
209
                    }
210
                    break;
211
                case Relation::ACTION_CASCADE: // Удалим все зависимые записи
212
                    foreach ($relatedRecords as $record) {
213
                        $result = $result && $record->checkRelationsSatisfaction($theFirstDeleteRecord, $record);
214
                        if ($result) {
215
                            $result = $record->delete();
216
                        }
217
                    }
218
                    break;
219
                case Relation::NO_ACTION: // Очистим ссылки на записи в таблицах зависимых
220
                    break;
221
                default:
222
                    break;
223
            }
224
        }
225
226
        return $result;
227
    }
228
229
    /**
230
     * После сохранения данных любой модели
231
     */
232
    public function afterSave(): void
233
    {
234
        $this->processSettingsChanges('afterSave');
235
        $this->clearCache(static::class);
236
    }
237
238
    /**
239
     * Готовит массив действий для перезапуска модулей ядра системы
240
     * и Asterisk
241
     *
242
     * @param $action string  быть afterSave или afterDelete
243
     */
244
    private function processSettingsChanges(string $action): void
245
    {
246
        if (php_sapi_name() !== 'cli') {
247
            if ( ! $this->hasSnapshotData()) {
248
                return;
249
            } // nothing changed
250
251
            $changedFields = $this->getUpdatedFields();
252
            if (empty($changedFields) && $action === 'afterSave') {
253
                return;
254
            }
255
256
            // Add changed fields set to benstalk queue
257
            $queue = $this->getDI()->getShared('beanstalkConnection');
258
259
            if ($this instanceof PbxSettings) {
260
                $id = $this->key;
261
            } else {
262
                $id = $this->id;
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on MikoPBX\Common\Models\ModelsBase. Since you implemented __get, consider adding a @property annotation.
Loading history...
263
            }
264
            $jobData = json_encode(
265
                [
266
                    'model'         => get_class($this),
267
                    'recordId'      => $id,
268
                    'action'        => $action,
269
                    'changedFields' => $changedFields,
270
                ]
271
            );
272
            $queue->publish($jobData);
273
        }
274
    }
275
276
    /**
277
     * Очистка кешей при сохранении данных в базу
278
     *
279
     * @param $calledClass string модель, с чей кеш будем чистить в полном формате
280
     */
281
    public function clearCache($calledClass): void
282
    {
283
        $managedCache = $this->getDI()->getManagedCache();
284
        $category     = explode('\\', $calledClass)[3];
285
        $keys         = $managedCache->getAdapter()->getKeys($category);
286
        if (count($keys) > 0) {
287
            $managedCache->deleteMultiple($keys);
288
        }
289
        if ($this->getDI()->has('modelsCache')) {
290
            $this->getDI()->get('modelsCache')->delete($category);
291
        }
292
    }
293
294
    /**
295
     * После удаления данных любой модели
296
     */
297
    public function afterDelete(): void
298
    {
299
        $this->processSettingsChanges('afterDelete');
300
        $this->clearCache(static::class);
301
    }
302
303
    /**
304
     * Возвращает предстваление элемента базы данных
305
     *  для сообщения об ошибках с ссылкой на элемент или для выбора в списках
306
     *  строкой
307
     *
308
     * @param bool $needLink - предстваление с ссылкой
309
     *
310
     * @return string
311
     */
312
    public function getRepresent($needLink = false): string
313
    {
314
        if ($this->id === null) {
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on MikoPBX\Common\Models\ModelsBase. Since you implemented __get, consider adding a @property annotation.
Loading history...
315
            return $this->t('mo_NewElement');
316
        }
317
318
        switch (static::class) {
319
            case AsteriskManagerUsers::class:
320
                $name = '<i class="asterisk icon"></i> ' . $this->username;
321
                break;
322
            case CallQueueMembers::class:
323
                $name = $this->Extensions->getRepresent();
324
                break;
325
            case CallQueues::class:
326
                $name = '<i class="users icon"></i> '
327
                    . $this->t('mo_CallQueueShort4Dropdown') . ': '
328
                    . $this->name;
329
                break;
330
            case ConferenceRooms::class:
331
                $name = '<i class="phone volume icon"></i> '
332
                    . $this->t('mo_ConferenceRoomsShort4Dropdown') . ': '
333
                    . $this->name;
334
                break;
335
            case CustomFiles::class:
336
                $name = "<i class='file icon'></i> {$this->filepath}";
337
                break;
338
            case DialplanApplications::class:
339
                $name = '<i class="php icon"></i> '
340
                    . $this->t('mo_ApplicationShort4Dropdown') . ': '
341
                    . $this->name;
342
                break;
343
            case ExtensionForwardingRights::class:
344
                $name = $this->Extensions->getRepresent();
345
                break;
346
            case Extensions::class:
347
                // Для внутреннего номера бывают разные представления
348
                if ($this->userid > 0) {
349
                    if ($this->type === 'EXTERNAL') {
350
                        $icon = '<i class="icons"><i class="user outline icon"></i><i class="top right corner alternate mobile icon"></i></i>';
351
                    } else {
352
                        $icon = '<i class="icons"><i class="user outline icon"></i></i>';
353
                    }
354
                    $name = '';
355
                    if (isset($this->Users->username)) {
356
                        $name = $this->trimName($this->Users->username);
357
                    }
358
359
                    $name = "{$icon} {$name} <{$this->number}>";
360
                } else {
361
                    switch (strtoupper($this->type)) {
362
                        case 'CONFERENCE':
363
                            $name = $this->ConferenceRooms->getRepresent();
364
                            break;
365
                        case 'QUEUE':
366
                            $name = $this->CallQueues->getRepresent();
367
                            break;
368
                        case 'DIALPLAN APPLICATION':
369
                            $name = $this->DialplanApplications->getRepresent();
370
                            break;
371
                        case 'IVR MENU':
372
                            $name = $this->IvrMenu->getRepresent();
373
                            break;
374
                        case 'MODULES':
375
                            $name = '<i class="puzzle piece icon"></i> '
376
                                . $this->t('mo_ModuleShort4Dropdown')
377
                                . ': '
378
                                . $this->callerid;
379
                            break;
380
                        case 'EXTERNAL':
381
                        case 'SIP':
382
                        default:
383
                            $name = "{$this->callerid} <{$this->number}>";
384
                    }
385
                }
386
                break;
387
            case ExternalPhones::class:
388
                $name = $this->Extensions->getRepresent();
389
                break;
390
            case Fail2BanRules::class:
391
                $name = '';
392
                break;
393
            case FirewallRules::class:
394
                $name = $this->category;
395
                break;
396
            case Iax::class:
397
                if ($this->disabled > 0) {
398
                    $name = "<i class='server icon'></i> {$this->description} ({$this->t( 'mo_Disabled' )})";
399
                } else {
400
                    $name = '<i class="server icon"></i> ' . $this->description;
401
                }
402
                break;
403
            case IvrMenu::class:
404
                $name = '<i class="sitemap icon"></i> '
405
                    . $this->t('mo_IVRMenuShort4Dropdown') . ': '
406
                    . $this->name;
407
                break;
408
            case IvrMenuActions::class:
409
                $name = $this->IvrMenu->name;
410
                break;
411
            case Codecs::class:
412
                $name = $this->name;
413
                break;
414
            case IaxCodecs::class:
415
                $name = $this->codec;
416
                break;
417
            case IncomingRoutingTable::class:
418
                $name = $this->t('mo_RightNumber', ['id' => $this->id]);
419
                break;
420
            case LanInterfaces::class:
421
                $name = $this->name;
422
                break;
423
            case NetworkFilters::class:
424
                $name = '<i class="globe icon"></i> ' . $this->description . '('
425
                    . $this->t('fw_PermitNetwork') . ': ' . $this->permit
426
                    . ')';
427
                break;
428
            case OutgoingRoutingTable::class:
429
                $name = $this->rulename;
430
                break;
431
            case OutWorkTimes::class:
432
                $name = '<i class="time icon"></i> ';
433
                if ( ! empty($this->description)) {
434
                    $name .= $this->description;
435
                } else {
436
                    $represent = '';
437
                    if (is_numeric($this->date_from)) {
438
                        $represent .= date("d/m/Y", $this->date_from) . '-';
439
                    }
440
                    if (is_numeric($this->date_to)) {
441
                        $represent .= date("d/m/Y", $this->date_to) . ' ';
442
                    }
443
                    if (isset($this->weekday_from)) {
444
                        $represent .= $this->t(date('D', strtotime("Sunday +{$this->weekday_from} days"))) . '-';
445
                    }
446
                    if (isset($this->weekday_to)) {
447
                        $represent .= $this->t(date('D', strtotime("Sunday +{$this->weekday_to} days"))) . ' ';
448
                    }
449
                    if (isset($this->time_from) || isset($this->time_to)) {
450
                        $represent .= $this->time_from . ' - ' . $this->time_to . ' ';
451
                    }
452
                    $name .= $this->t('repOutWorkTimes', ['represent' => $represent]);
453
                }
454
                break;
455
            case Providers::class:
456
                if ($this->type === "IAX") {
457
                    $name = $this->Iax->getRepresent();
458
                } else {
459
                    $name = $this->Sip->getRepresent();
460
                }
461
                break;
462
            case PbxSettings::class:
463
                $name = $this->key;
464
                break;
465
            case PbxExtensionModules::class:
466
                $name = '<i class="puzzle piece icon"></i> '
467
                    . $this->t('mo_ModuleShort4Dropdown') . ': '
468
                    . $this->name;
469
                break;
470
            case Sip::class:
471
                if ($this->Extensions) { // Это внутренний номер?
472
                    $name = $this->Extensions->getRepresent();
473
                } elseif ($this->Providers) { // Это провайдер
474
                    if ($this->disabled > 0) {
475
                        $name = "<i class='server icon'></i> {$this->description} ({$this->t( 'mo_Disabled' )})";
476
                    } else {
477
                        $name = '<i class="server icon"></i> '
478
                            . $this->description;
479
                    }
480
                } else { // Что это?
481
                    $name = $this->description;
482
                }
483
                break;
484
            case SipCodecs::class:
485
                $name = $this->codec;
486
                break;
487
            case Users::class:
488
                $name = '<i class="user outline icon"></i> ' . $this->username;
489
                break;
490
            case SoundFiles::class:
491
                $name = '<i class="file audio outline icon"></i> '
492
                    . $this->name;
493
                break;
494
            default:
495
              $name = 'Unknown';
496
497
        }
498
499
        if ($needLink) {
500
            if (empty($name)) {
0 ignored issues
show
introduced by
The condition empty($name) is always false.
Loading history...
501
                $name = $this->t('repLink');
502
            }
503
            $link     = $this->getWebInterfaceLink();
504
            $category = explode('\\', static::class)[3];
505
            $result   = $this->t(
506
                'rep' . $category,
507
                [
508
                    'represent' => "<a href='{$link}'>{$name}</a>",
509
                ]
510
            );
511
        } else {
512
            $result = $name;
513
        }
514
515
        return $result;
516
    }
517
518
    /**
519
     * Укорачивает длинные имена
520
     *
521
     * @param $s
522
     *
523
     * @return string
524
     */
525
    private function trimName($s): string
526
    {
527
        $max_length = 64;
528
529
        if (strlen($s) > $max_length) {
530
            $offset = ($max_length - 3) - strlen($s);
531
            $s      = substr($s, 0, strrpos($s, ' ', $offset)) . '...';
532
        }
533
534
        return $s;
535
    }
536
537
    /**
538
     * Return link on database record in web interface
539
     *
540
     * @return string
541
     */
542
    public function getWebInterfaceLink(): string
543
    {
544
        $url     = new Url();
545
        $link = '#';
546
        switch (static::class) {
547
            case AsteriskManagerUsers::class:
548
                $link = $url->get('asterisk-managers/modify/' . $this->id);
549
                break;
550
            case CallQueueMembers::class:
551
                $link = $url->get('call-queues/modify/' . $this->CallQueues->uniqid);
552
                break;
553
            case CallQueues::class:
554
                $link = $url->get('call-queues/modify/' . $this->uniqid);
555
                break;
556
            case ConferenceRooms::class:
557
                $link = $url->get('conference-rooms/modify/' . $this->uniqid);
558
                break;
559
            case CustomFiles::class:
560
                $link = $url->get('custom-files/modify/' . $this->id);
561
                break;
562
            case DialplanApplications::class:
563
                $link = $url->get('dialplan-applications/modify/' . $this->uniqid);
564
                break;
565
            case ExtensionForwardingRights::class:
566
567
                break;
568
            case Extensions::class:
569
                $link = $url->get('extensions/modify/' . $this->id);
570
                break;
571
            case ExternalPhones::class:
572
                if ($this->Extensions->is_general_user_number == 1) {
573
                    $parameters    = [
574
                        'conditions' => 'is_general_user_number=1 AND type="EXTERNAL" AND userid=:userid:',
575
                        'bind'       => [
576
                            'userid' => $this->Extensions->userid,
577
                        ],
578
                    ];
579
                    $needExtension = Extensions::findFirst($parameters);
580
                    $link          = $url->get('extensions/modify/' . $needExtension->id);
581
                } else {
582
                    $link = '#';//TODO сделать если будет раздел для допоплнинельных номеров пользователя
583
                }
584
                break;
585
            case Fail2BanRules::class:
586
                $link = '#';//TODO сделать если будет fail2ban
587
                break;
588
            case FirewallRules::class:
589
                $link = $url->get('firewall/modify/' . $this->NetworkFilters->id);
590
                break;
591
            case Iax::class:
592
                $link = $url->get('providers/modifyiax/' . $this->Providers->id);
593
                break;
594
            case IvrMenu::class:
595
                $link = $url->get('ivr-menu/modify/' . $this->uniqid);
596
                break;
597
            case IvrMenuActions::class:
598
                $link = $url->get('ivr-menu/modify/' . $this->IvrMenu->uniqid);
599
                break;
600
            case Codecs::class:
601
                break;
602
            case IaxCodecs::class:
603
                break;
604
            case IncomingRoutingTable::class:
605
                $link = $url->get('incoming-routes/modify/' . $this->id);
606
                break;
607
            case LanInterfaces::class:
608
                $link = $url->get('network/index/');
609
                break;
610
            case NetworkFilters::class:
611
                $link = $url->get('firewall/modify/' . $this->id);
612
                break;
613
            case OutgoingRoutingTable::class:
614
                $link = $url->get('outbound-routes/modify/' . $this->id);
615
                break;
616
            case OutWorkTimes::class:
617
                $link = $url->get('out-off-work-time/modify/' . $this->id);
618
                break;
619
            case Providers::class:
620
                if ($this->type === "IAX") {
621
                    $link = $url->get('providers/modifyiax/' . $this->uniqid);
622
                } else {
623
                    $link = $url->get('providers/modifysip/' . $this->uniqid);
624
                }
625
                break;
626
            case PbxSettings::class:
627
                $link = $url->get('general-settings/index');
628
                break;
629
            case PbxExtensionModules::class:
630
                $link = $url->get(Text::uncamelize($this->uniqid));
631
                break;
632
            case Sip::class:
633
                if ($this->Extensions) { // Это внутренний номер?
634
                    if ($this->Extensions->is_general_user_number === 1) {
635
                        $link = $url->get('extensions/modify/' . $this->Extensions->id);
636
                    } else {
637
                        $link = '#';//TODO сделать если будет раздел для допоплнинельных номеров пользователя
638
                    }
639
                } elseif ($this->Providers) { // Это провайдер
640
                    $link = $url->get('providers/modifysip/' . $this->Providers->id);
641
                }
642
                break;
643
            case SipCodecs::class:
644
                break;
645
            case Users::class:
646
                $parameters    = [
647
                    'conditions' => 'userid=:userid:',
648
                    'bind'       => [
649
                        'userid' => $this->id,
650
                    ],
651
                ];
652
                $needExtension = Extensions::findFirst($parameters);
653
                $link          = $url->get('extensions/modify/' . $needExtension->id);
654
                break;
655
            case SoundFiles::class:
656
                $link = $url->get('sound-files/modify/' . $this->id);
657
                break;
658
            default:
659
        }
660
661
        return $link;
662
    }
663
664
    /**
665
     * Возвращает массив полей, по которым следует добавить индекс в DB.
666
     * @return array
667
     */
668
    public function getIndexColumn():array {
669
        return [];
670
    }
671
}