Passed
Push — develop ( 558982...38f712 )
by Nikolay
06:07
created

IvrMenuController::deleteAction()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 31
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 31
rs 9.4222
c 0
b 0
f 0
cc 5
nc 6
nop 1
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright © 2017-2023 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
namespace MikoPBX\AdminCabinet\Controllers;
21
22
use MikoPBX\AdminCabinet\Forms\IvrMenuEditForm;
23
use MikoPBX\Common\Models\{Extensions, IvrMenu, IvrMenuActions, SoundFiles};
24
25
class IvrMenuController extends BaseController
26
{
27
28
29
    /**
30
     * Builds the IVR menu representation.
31
     *
32
     * This method retrieves IVR menu actions and IVR menus from the database and constructs the representation
33
     * of the IVR menu, including its actions and related information.
34
     */
35
    public function indexAction(): void
36
    {
37
        $records = IvrMenuActions::find();
38
        $ivrMenuActions=[];
39
        foreach ($records as $record) {
40
            $ivrMenuActions[$record->ivr_menu_id][$record->id]=[
41
                'digits'=>$record->digits,
42
                'represent'=>$record->Extensions===null?'ERROR':$record->Extensions->getRepresent()
43
            ];
44
        }
45
46
        $records = IvrMenu::find();
47
        $ivrMenuList=[];
48
49
        // Retrieve IVR menus and build the representation
50
        foreach ($records as $record) {
51
            usort($ivrMenuActions[$record->uniqid], [__CLASS__, 'sortArrayByDigits']);
52
            $ivrMenuList[]=[
53
                'uniqid'=>$record->uniqid,
54
                'name'=>$record->name,
55
                'extension'=>$record->extension,
56
                'actions'=>$ivrMenuActions[$record->uniqid],
57
                'description'=>$record->description,
58
                'timeoutExtension'=>$record->TimeoutExtensions===null?'ERROR':$record->TimeoutExtensions->getRepresent()
59
            ];
60
        }
61
        $this->view->ivrmenu = $ivrMenuList;
62
    }
63
64
    /**
65
     * Modify IVR menu action.
66
     *
67
     * This method is responsible for modifying an IVR menu action. It retrieves the IVR menu and related data
68
     * from the database, including IVR menu actions, sound files, and extensions. It constructs the form for
69
     * modifying the IVR menu and populates it with the retrieved data. It assigns the form, IVR menu actions,
70
     * representation, and extension to the view for rendering.
71
     *
72
     * @param string $ivrmenuid - The ID of the IVR menu to modify.
73
     */
74
    public function modifyAction(string $ivrmenuid = ''): void
75
    {
76
        // Retrieve the IVR menu by ID
77
        $ivrmenu                = IvrMenu::findFirstByUniqid($ivrmenuid);
78
        $ivrActionsList         = [];
79
        $soundfilesList         = [];
80
        $extensionList          = [];
81
        $soundfilesList[""]     = $this->translation->_("sf_SelectAudioFile");
82
        $extensionList[""]      = $this->translation->_("ex_SelectNumber");
83
        $extensionListForFilter = [];
84
        if ($ivrmenu === null) {
85
            // Create a new IVR menu if not found
86
            $ivrmenu                   = new IvrMenu();
87
            $ivrmenu->uniqid           = strtoupper('IVR-' . md5($ivrmenu->id . time()));
88
            $ivrmenu->number_of_repeat = 3;
89
            $ivrmenu->extension
90
                                       = Extensions::getNextFreeApplicationNumber();
91
            $ivrmenu->timeout          = 7;
92
        } else {
93
            $extensionListForFilter[] = $ivrmenu->timeout_extension;
94
95
            // Retrieve IVR menu actions related to the IVR menu
96
            $parameters = [
97
                'conditions' => 'ivr_menu_id=:menu:',
98
                'bind'       => [
99
                    'menu' => $ivrmenu->uniqid,
100
                ],
101
            ];
102
            $actions    = IvrMenuActions::find($parameters);
103
            foreach ($actions as $action) {
104
                $represent = $action->Extensions===null?"ERROR":$action->Extensions->getRepresent();
105
                // Build IVR menu actions array
106
                $ivrActionsList[]         = [
107
                    'id'                 => $action->id,
108
                    'extension'          => $action->extension,
109
                    'extensionRepresent' => str_replace(
110
                        '"',
111
                        '\\"',
112
                        $represent
113
                    ),
114
                    'digits'             => $action->digits,
115
                ];
116
                $extensionListForFilter[] = $action->extension;
117
            }
118
        }
119
        usort($ivrActionsList, [__CLASS__, 'sortArrayByDigits']);
120
121
        if (count($extensionListForFilter) > 0) {
122
            $parameters = [
123
                'conditions' => 'number IN ({ids:array})',
124
                'bind'       => [
125
                    'ids' => $extensionListForFilter,
126
                ],
127
            ];
128
            $extensions = Extensions::find($parameters);
129
            foreach ($extensions as $record) {
130
                $extensionList[$record->number] = $record->getRepresent();
131
            }
132
        }
133
134
        // Retrieve custom sound files for IVR
135
        $soundFiles = SoundFiles::find('category="custom"');
136
        foreach ($soundFiles as $soundFile) {
137
            $soundfilesList[$soundFile->id] = $soundFile->getRepresent();
138
        }
139
140
        // Construct the form for modifying the IVR menu
141
        $form                   = new IvrMenuEditForm(
142
            $ivrmenu, [
143
            'extensions' => $extensionList,
144
            'soundfiles' => $soundfilesList,
145
        ]
146
        );
147
148
        // Assign data to the view for rendering
149
        $this->view->form       = $form;
150
        $this->view->ivractions = $ivrActionsList;
151
        $this->view->represent  = $ivrmenu->getRepresent();
152
        $this->view->extension  = $ivrmenu->extension;
153
154
    }
155
156
    /**
157
     * Sorts array by digits field
158
     *
159
     * @param $a
160
     * @param $b
161
     *
162
     * @return int|null
163
     */
164
    public function sortArrayByDigits($a, $b): ?int
165
    {
166
        $a = (int)$a['digits'];
167
        $b = (int)$b['digits'];
168
        if ($a === $b) {
169
            return 0;
170
        } else {
171
            return ($a < $b) ? -1 : 1;
172
        }
173
    }
174
175
    /**
176
     * Saves the IVR menu
177
     */
178
    public function saveAction(): void
179
    {
180
        if ( ! $this->request->isPost()) {
181
            return;
182
        }
183
184
        $this->db->begin();
185
186
        $data          = $this->request->getPost();
187
        $ivrMenuRecord = IvrMenu::findFirstByUniqid($data['uniqid']);
188
        if ($ivrMenuRecord === null) {
189
            $ivrMenuRecord = new IvrMenu();
190
            $extension                    = new Extensions();
191
            $extension->type              = Extensions::TYPE_IVR_MENU;
192
            $extension->number            = $data["extension"];
193
            $extension->callerid          = $this->sanitizeCallerId($data["name"]);
194
            $extension->userid            = null;
195
            $extension->show_in_phonebook = 1;
196
            $extension->public_access     = 1;
197
        } else {
198
            $extension = $ivrMenuRecord->Extensions;
199
        }
200
201
        // Update IVR menu parameters
202
        if ( ! $this->updateExtension($extension, $data)) {
203
            $this->view->success = false;
204
            $this->db->rollback();
205
206
            return;
207
        }
208
209
        // Update IVR menu actions
210
        if ( ! $this->updateIVRMenu($ivrMenuRecord, $data)) {
211
            $this->view->success = false;
212
            $this->db->rollback();
213
214
            return;
215
        }
216
217
        // Update IVR menu actions
218
        if ( ! $this->updateIVRMenuActions($data)) {
219
            $this->view->success = false;
220
            $this->db->rollback();
221
222
            return;
223
        }
224
225
        $this->view->success = true;
226
        $this->db->commit();
227
228
        // If it was the creation of a new IVR menu, reload the page with the specified ID
229
        if (empty($data['id'])) {
230
            $this->view->reload = "ivr-menu/modify/{$data['uniqid']}";
231
        }
232
    }
233
234
    /**
235
     * Update parameters of an internal extension.
236
     *
237
     * @param \MikoPBX\Common\Models\Extensions $extension The extension object to update.
238
     * @param array                             $data      An array of fields from the POST request.
239
     *
240
     * @return bool The update result.
241
     */
242
    private function updateExtension(Extensions $extension, array $data): bool
243
    {
244
        $extension->number   = $data['extension'];
245
        $extension->callerid = $this->sanitizeCallerId($data['name']);
246
        if ($extension->save() === false) {
247
            $errors = $extension->getMessages();
248
            $this->flash->error(implode('<br>', $errors));
249
250
            return false;
251
        }
252
253
        return true;
254
    }
255
256
    /**
257
     * Update parameters of an IVR menu.
258
     *
259
     * @param \MikoPBX\Common\Models\IvrMenu $ivrMenu The IVR menu object to update.
260
     * @param array                          $data    An array of fields from the POST request.
261
     *
262
     * @return bool The update result.
263
     */
264
    private function updateIVRMenu(IvrMenu $ivrMenu, array $data): bool
265
    {
266
        // Заполним параметры записи Ivr Menu
267
        foreach ($ivrMenu as $name => $value) {
268
            switch ($name) {
269
                case "extension":
270
                case "name":
271
                    $ivrMenu->$name = $data[$name];
272
                    break;
273
                case "allow_enter_any_internal_extension":
274
                    if (array_key_exists($name, $data) && $data[$name] == "on") {
275
                        $ivrMenu->$name = "1";
276
                    } else {
277
                        $ivrMenu->$name = "0";
278
                    }
279
                    break;
280
                default:
281
                    if ( ! array_key_exists($name, $data)) {
282
                        continue 2;
283
                    }
284
                    $ivrMenu->$name = $data[$name];
285
            }
286
        }
287
        if ($ivrMenu->save() === false) {
288
            $errors = $ivrMenu->getMessages();
289
            $this->flash->error(implode('<br>', $errors));
290
291
            return false;
292
        }
293
294
        return true;
295
    }
296
297
    /**
298
     * Update parameters of IVR menu actions.
299
     *
300
     * @param array $data An array of fields from the POST request.
301
     *
302
     * @return bool The update result.
303
     */
304
    private function updateIVRMenuActions(array $data): bool
305
    {
306
        $existDigits = [];
307
308
        // Update or create IVRMenuActions
309
        $arrActions = json_decode($data['actions']);
310
        foreach ($arrActions as $value) {
311
            $parameters = [
312
                'conditions' => 'ivr_menu_id = :uniqid: AND digits=:digits:',
313
                'bind'       => [
314
                    'digits' => $value->digits,
315
                    'uniqid' => $data['uniqid'],
316
                ],
317
            ];
318
            $newRule    = IvrMenuActions::findFirst($parameters);
319
            if ($newRule === null) {
320
                $newRule              = new IvrMenuActions();
321
                $newRule->digits      = $value->digits;
322
                $newRule->ivr_menu_id = $data['uniqid'];
323
            }
324
            $newRule->extension = $value->extension;
325
            if ($newRule->save() === false) {
326
                $errors = $newRule->getMessages();
327
                $this->flash->warning(implode('<br>', $errors));
328
                $this->view->success = false;
329
330
                return false;
331
            }
332
            $existDigits[] = $value->digits;
333
        }
334
335
        // Delete unnecessary IVRMenuActions
336
        $parameters = [
337
            'conditions' => 'digits NOT IN ({numbers:array}) AND ivr_menu_id=:uniqid:',
338
            'bind'       => [
339
                'numbers' => $existDigits,
340
                'uniqid'  => $data['uniqid'],
341
            ],
342
        ];
343
344
        $deletedActions = IvrMenuActions::find($parameters);
345
        if ($deletedActions && $deletedActions->delete() === false) {
346
            $errors = $deletedActions->getMessages();
347
            $this->flash->error(implode('<br>', $errors));
348
349
            return false;
350
        }
351
352
        return true;
353
    }
354
355
}