1
|
|
|
<?php |
|
|
|
|
2
|
|
|
|
3
|
|
|
namespace DigitalWand\AdminHelper\Helper; |
4
|
|
|
|
5
|
|
|
use Bitrix\Main\Loader; |
6
|
|
|
use Bitrix\Main\LoaderException; |
7
|
|
|
use Bitrix\Main\Localization\Loc; |
8
|
|
|
use Bitrix\Main\ModuleManager; |
9
|
|
|
use DigitalWand\AdminHelper\EntityManager; |
10
|
|
|
use DigitalWand\AdminHelper\Widget\HelperWidget; |
11
|
|
|
use Bitrix\Main\Entity\DataManager; |
12
|
|
|
use Bitrix\Highloadblock as HL; |
13
|
|
|
use Bitrix\Main\Context; |
14
|
|
|
|
15
|
|
|
Loader::includeModule('highloadblock'); |
16
|
|
|
Loc::loadMessages(__FILE__); |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Данный модуль реализует подход MVC для создания административного интерфейса. |
20
|
|
|
* |
21
|
|
|
* Возможность построения административного интерфейса появляется благодаря наличию единого API для CRUD-операциями над |
22
|
|
|
* сущностями. Поэтому построение админ. интерфейса средствами данного модуля возможно только для классов, реализующих |
23
|
|
|
* API ORM Битрикс. При желании использовать данный модуль для сущностей, не использующих ORM Битрикс, можно |
24
|
|
|
* подготовить для таких сущностей класс-обёртку, реализующий необходимые функции. |
25
|
|
|
* |
26
|
|
|
* Основные понятия модуля: |
27
|
|
|
* <ul> |
28
|
|
|
* <li>Мдель: "model" в терминах MVC. Класс, унаследованный от DataManager или реализующий аналогичный API.</li> |
29
|
|
|
* <li>Хэлпер: "view" в терминах MVC. Класс, реализующий отрисовку интерфейса списка или детальной страницы.</li> |
30
|
|
|
* <li>Роутер: "controller" в терминах MVC. Файл, принимающий все запросы к админке данного модуля, создающий нужные |
31
|
|
|
* хэлперы с нужными настройками. С ним напрямую работать не придётся.</li> |
32
|
|
|
* <li>Виджеты: "delegate" в терминах MVC. Классы, отвечающие за отрисовку элементов управления для отдельных полей |
33
|
|
|
* сущностей. В списке и на детальной.</li> |
34
|
|
|
* </ul> |
35
|
|
|
* |
36
|
|
|
* Схема работы с модулем следующая: |
37
|
|
|
* <ul> |
38
|
|
|
* <li>Реализация класса AdminListHelper - для управления страницей списка элементов</li> |
39
|
|
|
* <li>Реализация класса AdminEditHelper - для управления страницей просмотра/редактирования элемента</li> |
40
|
|
|
* <li>Реализация класса AdminInterface - для описания конфигурации полей админки и классы интерфейсов</li> |
41
|
|
|
* <li>Реализация класса AdminSectionListHelper - для описания странице списка разделов(если они используются)</li> |
42
|
|
|
* <li>Реализация класса AdminSectionEditHelper - для управления страницей просмотра/редактирования раздела(если они используются)</li> |
43
|
|
|
* <li>Если не хватает возможностей виджетов, идущих с модулем, можно реализовать свой виджет, унаследованный от любого |
44
|
|
|
* другого готового виджета или от абстрактного класса HelperWidget</li> |
45
|
|
|
* </ul> |
46
|
|
|
* |
47
|
|
|
* Устаревший функционал: |
48
|
|
|
* <ul> |
49
|
|
|
* <li>Файл Interface.php с вызовом AdminBaseHelper::setInterfaceSettings(), в который передается |
50
|
|
|
* конфигурация полей админки и классы.</li> |
51
|
|
|
* |
52
|
|
|
* Рекомендуемая файловая структура для модулей, использующих данный функционал: |
53
|
|
|
* <ul> |
54
|
|
|
* <li>Каталог <b>admin</b>. Достаточно поместить в него файл menu.php, отдельные файлы для списка и детальной |
55
|
|
|
* создавать не надо благодаря единому роутингу.</li> |
56
|
|
|
* <li>Каталог <b>classes</b> (или lib): содержит классы модли, представлений и делегатов.</li> |
57
|
|
|
* <li> -- <b>classes/admininterface</b>: каталог, содержащий классы "view", унаследованные от AdminListHelper, |
58
|
|
|
* AdminEditHelper, AdminInterface, AdminSectionListHelper и AdminSectionEditHelper.</li> |
59
|
|
|
* <li> -- <b>classes/widget</b>: каталог, содержащий виджеты ("delegate"), если для модуля пришлось создавать |
60
|
|
|
* свои.</li> |
61
|
|
|
* <li> -- <b>classes/model</b>: каталог с моделями, если пришлось переопределять поведение стандартынх функций getList |
62
|
|
|
* и т.д.</li> |
63
|
|
|
* </ul> |
64
|
|
|
* |
65
|
|
|
* Использовать данную структуру не обязательно, это лишь рекомендация, основанная на успешном опыте применения модуля |
66
|
|
|
* в ряде проектов. |
67
|
|
|
* |
68
|
|
|
* Единственное <b>обязательное</b> условие - расположение всех реализуемых классов админ хелперов и админ интерфейсов |
69
|
|
|
* в одном неймспейсе |
70
|
|
|
* |
71
|
|
|
* При использовании разделов нужно обязательно прописать в модели элементов привязку к модели разделов, например: |
72
|
|
|
* |
73
|
|
|
* ```php |
74
|
|
|
* <?php |
75
|
|
|
* class ElementModel |
76
|
|
|
* { |
77
|
|
|
* public static function getMap() |
78
|
|
|
* { |
79
|
|
|
* return [ |
80
|
|
|
* 'CATEGORY' => [ |
81
|
|
|
* 'data_type' => 'Vendor\Module\CategoryTable', |
82
|
|
|
* 'reference' => ['=this.CATEGORY_ID' => 'ref.ID'], |
83
|
|
|
* ] |
84
|
|
|
* ]; |
85
|
|
|
* } |
86
|
|
|
* ``` |
87
|
|
|
* |
88
|
|
|
* @see AdminInterface::fields() |
89
|
|
|
* @package AdminHelper |
90
|
|
|
* |
91
|
|
|
* @author Nik Samokhvalov <[email protected]> |
92
|
|
|
* @author Artem Yarygin <[email protected]> |
93
|
|
|
*/ |
94
|
|
|
abstract class AdminBaseHelper |
95
|
|
|
{ |
96
|
|
|
/** |
97
|
|
|
* @internal |
98
|
|
|
* @var string адрес обработчика запросов к админ. интерфейсу. |
99
|
|
|
*/ |
100
|
|
|
static protected $routerUrl = '/bitrix/admin/admin_helper_route.php'; |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* @var string |
104
|
|
|
* Имя класса используемой модели. Используется для выполнения CRUD-операций. |
105
|
|
|
* При наследовании класса необходимо переопределить эту переменную, указав полное имя класса модели. |
106
|
|
|
* |
107
|
|
|
* @see DataManager |
108
|
|
|
* @api |
109
|
|
|
*/ |
110
|
|
|
static protected $model; |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @var string |
114
|
|
|
* Имя класса используемого менеджера сущностей. Используется для выполнения CRUD-операций. |
115
|
|
|
* |
116
|
|
|
* @see DataManager |
117
|
|
|
* @api |
118
|
|
|
*/ |
119
|
|
|
static protected $entityManager = '\DigitalWand\AdminHelper\EntityManager'; |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* @var string |
123
|
|
|
* Назвние модуля данной модели. |
124
|
|
|
* При наследовании класса необходимо указать нзвание модуля, в котором он находится. |
125
|
|
|
* А можно и не указывать, в этому случае он определится автоматически по namespace класса |
126
|
|
|
* Используется для избежания конфликтов между именами представлений. |
127
|
|
|
* |
128
|
|
|
* @api |
129
|
|
|
*/ |
130
|
|
|
static public $module = array(); |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* @var string[] |
134
|
|
|
* Название представления. |
135
|
|
|
* При наследовании класса необходимо указать название представления. |
136
|
|
|
* А можно и не указывать, в этому случае оно определится автоматически по namespace класса. |
137
|
|
|
* Оно будет использовано при построении URL к данному разделу админки. |
138
|
|
|
* Не должно содержать пробелов и других символов, требующих преобразований для |
139
|
|
|
* адресной строки браузера. |
140
|
|
|
* |
141
|
|
|
* @api |
142
|
|
|
*/ |
143
|
|
|
static protected $viewName = array(); |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* @var array |
147
|
|
|
* Настройки интерфейса |
148
|
|
|
* @see AdminBaseHelper::setInterfaceSettings() |
149
|
|
|
* @internal |
150
|
|
|
*/ |
151
|
|
|
static protected $interfaceSettings = array(); |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* @var array |
155
|
|
|
* Привязка класса интерфеса к классу хелпера |
156
|
|
|
*/ |
157
|
|
|
static protected $interfaceClass = array(); |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* @var array |
161
|
|
|
* Хранит список отображаемых полей и настройки их отображения |
162
|
|
|
* @see AdminBaseHelper::setInterfaceSettings() |
163
|
|
|
*/ |
164
|
|
|
protected $fields = array(); |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* @var \CMain |
168
|
|
|
* Замена global $APPLICATION; |
169
|
|
|
*/ |
170
|
|
|
protected $app; |
171
|
|
|
protected $validationErrors = array(); |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* @var string |
175
|
|
|
* Позволяет непосредственно указать адрес страницы списка. Полезно, в случае, если такая станица реализована без |
176
|
|
|
* использования данного модуля. В случае, если поле определено для класса, роутинг не используется. |
177
|
|
|
* |
178
|
|
|
* @see AdminBaseHelper::getListPageUrl |
179
|
|
|
* @api |
180
|
|
|
*/ |
181
|
|
|
static protected $listPageUrl; |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* @var string |
185
|
|
|
* $viewName представления, отвечающего за страницу списка. Необходимо указывать только для классов, уналедованных |
186
|
|
|
* от AdminEditHelper. |
187
|
|
|
* Необязательное, сгенерируется автоматически если не определено |
188
|
|
|
* |
189
|
|
|
* @see AdminBaseHelper::getViewName() |
190
|
|
|
* @see AdminBaseHelper::getListPageUrl |
191
|
|
|
* @see AdminEditHelper |
192
|
|
|
* @api |
193
|
|
|
*/ |
194
|
|
|
static protected $listViewName; |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* @var string |
198
|
|
|
* Позволяет непосредственно указать адрес страницы просмотра/редактирования элемента. Полезно, в случае, если |
199
|
|
|
* такая станица реализована без использования данного модуля. В случае, если поле определено для класса, |
200
|
|
|
* роутинг не используется. |
201
|
|
|
* |
202
|
|
|
* @see AdminBaseHelper::getEditPageUrl |
203
|
|
|
* @api |
204
|
|
|
*/ |
205
|
|
|
static protected $editPageUrl; |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* @var string |
209
|
|
|
* $viewName представления, отвечающего за страницу редактирования/просмотра элемента. Необходимо указывать только |
210
|
|
|
* для классов, уналедованных от AdminListHelper. |
211
|
|
|
* |
212
|
|
|
* @see AdminBaseHelper::getViewName() |
213
|
|
|
* @see AdminBaseHelper::getEditPageUrl |
214
|
|
|
* @see AdminListHelper |
215
|
|
|
* @api |
216
|
|
|
*/ |
217
|
|
|
static protected $editViewName; |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* @var string |
221
|
|
|
* Позволяет непосредственно указать адрес страницы просмотра/редактирования раздела. Полезно, в случае, если |
222
|
|
|
* такая станица реализована без использования данного модуля. В случае, если поле определено для класса, |
223
|
|
|
* роутинг не используется. |
224
|
|
|
* |
225
|
|
|
* @see AdminBaseHelper::getEditPageUrl |
226
|
|
|
* @api |
227
|
|
|
*/ |
228
|
|
|
static protected $sectionsEditPageUrl; |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* @var string |
232
|
|
|
* $viewName представления, отвечающего за страницу редактирования/просмотра раздела. Необходимо указывать только |
233
|
|
|
* для классов, уналедованных от AdminListHelper. |
234
|
|
|
* Необязательное, сгенерируется автоматически если не определено |
235
|
|
|
* |
236
|
|
|
* @see AdminBaseHelper::getViewName() |
237
|
|
|
* @see AdminBaseHelper::getEditPageUrl |
238
|
|
|
* @see AdminListHelper |
239
|
|
|
* @api |
240
|
|
|
*/ |
241
|
|
|
static protected $sectionsEditViewName; |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* @var array |
245
|
|
|
* Дополнительные параметры URL, которые будут добавлены к параметрам по-умолчанию, генерируемым автоматически |
246
|
|
|
* @api |
247
|
|
|
*/ |
248
|
|
|
protected $additionalUrlParams = array(); |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* @var string контекст выполнения. Полезен для информирования виджетов о том, какая операция в настоящий момент |
252
|
|
|
* производится. |
253
|
|
|
*/ |
254
|
|
|
protected $context = ''; |
255
|
|
|
|
256
|
|
|
/** |
257
|
|
|
* Флаг использования разделов, необходимо переопределять в дочернем классе |
258
|
|
|
* @var bool |
259
|
|
|
*/ |
260
|
|
|
static protected $useSections = false; |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* Правило именования хелперов для разделов по умолчанию |
264
|
|
|
* @var string |
265
|
|
|
*/ |
266
|
|
|
static protected $sectionSuffix = 'Sections'; |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* @param array $fields список используемых полей и виджетов для них |
270
|
|
|
* @param array $tabs список вкладок для детальной страницы |
271
|
|
|
* @param string $module название модуля |
272
|
|
|
*/ |
273
|
|
|
public function __construct(array $fields, array $tabs = array(), $module = "") |
|
|
|
|
274
|
|
|
{ |
275
|
|
|
global $APPLICATION; |
|
|
|
|
276
|
|
|
|
277
|
|
|
$this->app = $APPLICATION; |
278
|
|
|
|
279
|
|
|
$settings = array( |
280
|
|
|
'FIELDS' => $fields, |
281
|
|
|
'TABS' => $tabs |
282
|
|
|
); |
283
|
|
|
if (static::setInterfaceSettings($settings)) { |
284
|
|
|
$this->fields = $fields; |
285
|
|
|
} |
286
|
|
|
else { |
287
|
|
|
$settings = static::getInterfaceSettings(); |
288
|
|
|
$this->fields = $settings['FIELDS']; |
289
|
|
|
} |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* @param string $viewName Имя вьюхи, для которой мы хотим получить натсройки |
294
|
|
|
* |
295
|
|
|
* @return array Возвращает настройки интерфейса для данного класса. |
296
|
|
|
* |
297
|
|
|
* @see AdminBaseHelper::setInterfaceSettings() |
298
|
|
|
* @api |
299
|
|
|
*/ |
300
|
|
|
public static function getInterfaceSettings($viewName = '') |
301
|
|
|
{ |
302
|
|
|
if (empty($viewName)) { |
303
|
|
|
$viewName = static::getViewName(); |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
return self::$interfaceSettings[static::getModule()][$viewName]['interface']; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* Основная функция для конфигурации всего административного интерфейса. |
311
|
|
|
* |
312
|
|
|
* @param array $settings настройки полей и вкладок |
313
|
|
|
* @param array $helpers список классов-хэлперов, используемых для отрисовки админки |
314
|
|
|
* @param string $module название модуля |
315
|
|
|
* |
316
|
|
|
* @return bool false, если для данного класса уже были утановлены настройки |
317
|
|
|
* |
318
|
|
|
* @api |
319
|
|
|
*/ |
320
|
|
|
public static function setInterfaceSettings(array $settings, array $helpers = array(), $module = '') |
321
|
|
|
{ |
322
|
|
|
foreach ($helpers as $helperClass => $helperSettings) { |
323
|
|
|
if (!is_array($helperSettings)) { // поддержка старого формата описания хелперов |
324
|
|
|
$helperClass = $helperSettings; // в значении передается класс хелпера а не настройки |
325
|
|
|
$helperSettings = array(); // настроек в старом формате нет |
326
|
|
|
} |
327
|
|
|
$success = $helperClass::registerInterfaceSettings($module, array_merge($settings, $helperSettings)); |
328
|
|
|
if (!$success) return false; |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
return true; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
/** |
335
|
|
|
* Привязывает класса хелпера из которого вызывается к интерфесу, используется при получении |
336
|
|
|
* данных об элементах управления из интерфейса. |
337
|
|
|
* |
338
|
|
|
* @param $class |
339
|
|
|
*/ |
340
|
|
|
public static function setInterfaceClass($class) |
341
|
|
|
{ |
342
|
|
|
static::$interfaceClass[get_called_class()] = $class; |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Возвращает класс интерфейса к которому привязан хелпер из которого вызван метод. |
347
|
|
|
* |
348
|
|
|
* @return array |
349
|
|
|
*/ |
350
|
|
|
public static function getInterfaceClass() |
351
|
|
|
{ |
352
|
|
|
return isset(static::$interfaceClass[get_called_class()]) ? static::$interfaceClass[get_called_class()] : false; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* Регистрирует настройки интерфейса для текущего хелпера |
357
|
|
|
* |
358
|
|
|
* @param string $module имя текущего модуля |
359
|
|
|
* @param $interfaceSettings |
360
|
|
|
* |
361
|
|
|
* @return bool |
362
|
|
|
* @internal |
363
|
|
|
*/ |
364
|
|
|
public static function registerInterfaceSettings($module, $interfaceSettings) |
365
|
|
|
{ |
366
|
|
|
if (isset(self::$interfaceSettings[$module][static::getViewName()]) || empty($module) |
367
|
|
|
|| empty($interfaceSettings) |
368
|
|
|
) { |
369
|
|
|
return false; |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
self::$interfaceSettings[$module][static::getViewName()] = array( |
373
|
|
|
'helper' => get_called_class(), |
374
|
|
|
'interface' => $interfaceSettings |
375
|
|
|
); |
376
|
|
|
|
377
|
|
|
return true; |
378
|
|
|
} |
379
|
|
|
|
380
|
|
|
/** |
381
|
|
|
* Получает настройки интерфейса для данного модуля и представления. Используется при роутинге. |
382
|
|
|
* Возвращается массив со следующими ключами: |
383
|
|
|
* |
384
|
|
|
* <ul> |
385
|
|
|
* <li> helper - название класса-хэлпера, который будет рисовать страницу</li> |
386
|
|
|
* <li> interface - настройки интерфейса для хелпера</li> |
387
|
|
|
* </ul> |
388
|
|
|
* |
389
|
|
|
* @param string $module Модуль, для которого нужно получить настройки. |
390
|
|
|
* @param string $view Название представления. |
391
|
|
|
* |
392
|
|
|
* @return array |
393
|
|
|
* @internal |
394
|
|
|
*/ |
395
|
|
|
public static function getGlobalInterfaceSettings($module, $view) |
396
|
|
|
{ |
397
|
|
|
if (!isset(self::$interfaceSettings[$module][$view])) { |
398
|
|
|
return false; |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
return array( |
402
|
|
|
self::$interfaceSettings[$module][$view]['helper'], |
403
|
|
|
self::$interfaceSettings[$module][$view]['interface'], |
404
|
|
|
); |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* Возвращает имя текущего представления. |
409
|
|
|
* |
410
|
|
|
* @return string |
411
|
|
|
* @api |
412
|
|
|
*/ |
413
|
|
|
public static function getViewName() |
414
|
|
|
{ |
415
|
|
|
if (!is_array(static::$viewName)) { |
416
|
|
|
return static::$viewName; |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
$className = get_called_class(); |
420
|
|
|
|
421
|
|
|
if (!isset(static::$viewName[$className])) { |
422
|
|
|
$classNameParts = explode('\\', trim($className, '\\')); |
423
|
|
|
|
424
|
|
|
if (count($classNameParts) > 2) { |
425
|
|
|
$classCaption = array_pop($classNameParts); // название класса без namespace |
426
|
|
|
preg_match_all('/((?:^|[A-Z])[a-z]+)/', $classCaption, $matches); |
427
|
|
|
$classCaptionParts = $matches[0]; |
428
|
|
|
|
429
|
|
|
if (end($classCaptionParts) == 'Helper') { |
430
|
|
|
array_pop($classCaptionParts); |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
static::$viewName[$className] = strtolower(implode('_', $classCaptionParts)); |
434
|
|
|
} |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
return static::$viewName[$className]; |
438
|
|
|
} |
439
|
|
|
|
440
|
|
|
/** |
441
|
|
|
* Возвращает поле модели которое используется для привязки к разделу из поля с типом совпадающим с классом модели |
442
|
|
|
* раздела. |
443
|
|
|
* @return string |
444
|
|
|
* @throws Exception |
445
|
|
|
*/ |
446
|
|
|
public static function getSectionField() |
447
|
|
|
{ |
448
|
|
|
$sectionListHelper = static::getHelperClass(AdminSectionListHelper::className()); |
449
|
|
|
|
450
|
|
|
if (empty($sectionListHelper)) |
451
|
|
|
{ |
452
|
|
|
return null; |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
$sectionModelClass = $sectionListHelper::getModel(); |
456
|
|
|
$modelClass = static::getModel(); |
457
|
|
|
|
458
|
|
|
foreach ($modelClass::getMap() as $field => $data) { |
459
|
|
|
if ($data['data_type'] === $sectionModelClass) { |
460
|
|
|
return str_replace('=this.', '', key($data['reference'])); |
461
|
|
|
} |
462
|
|
|
} |
463
|
|
|
|
464
|
|
|
throw new Exception('References to section model not found'); |
465
|
|
|
} |
466
|
|
|
|
467
|
|
|
/** |
468
|
|
|
* Возвращает имя класса используемой модели. |
469
|
|
|
* |
470
|
|
|
* @return \Bitrix\Main\Entity\DataManager|string |
471
|
|
|
* |
472
|
|
|
* @throws \Bitrix\Main\ArgumentException |
473
|
|
|
* @throws \Bitrix\Main\SystemException |
474
|
|
|
* @throws \Exception |
475
|
|
|
* @api |
476
|
|
|
*/ |
477
|
|
|
public static function getModel() |
478
|
|
|
{ |
479
|
|
|
if (static::$model) { |
480
|
|
|
return static::getHLEntity(static::$model); |
481
|
|
|
} |
482
|
|
|
|
483
|
|
|
return null; |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
/** |
487
|
|
|
* Возвращает имя модуля. Если оно не задано, то определяет автоматически из namespace класса. |
488
|
|
|
* |
489
|
|
|
* @return string |
490
|
|
|
* |
491
|
|
|
* @throws LoaderException |
492
|
|
|
* @api |
493
|
|
|
*/ |
494
|
|
|
public static function getModule() |
495
|
|
|
{ |
496
|
|
|
if (!is_array(static::$module)) { |
497
|
|
|
return static::$module; |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
$className = get_called_class(); |
501
|
|
|
|
502
|
|
|
if (!isset(static::$module[$className])) { |
503
|
|
|
$classNameParts = explode('\\', trim($className, '\\')); |
504
|
|
|
|
505
|
|
|
$moduleNameParts = array(); |
506
|
|
|
$moduleName = false; |
507
|
|
|
|
508
|
|
|
while (count($classNameParts)) { |
509
|
|
|
$moduleNameParts[] = strtolower(array_shift($classNameParts)); |
510
|
|
|
$moduleName = implode('.', $moduleNameParts); |
511
|
|
|
|
512
|
|
|
if (ModuleManager::isModuleInstalled($moduleName)) { |
513
|
|
|
static::$module[$className] = $moduleName; |
514
|
|
|
break; |
515
|
|
|
} |
516
|
|
|
} |
517
|
|
|
|
518
|
|
|
if (empty($moduleName)) { |
519
|
|
|
throw new LoaderException('Module name not found'); |
520
|
|
|
} |
521
|
|
|
} |
522
|
|
|
|
523
|
|
|
return static::$module[$className]; |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
/** |
527
|
|
|
* Возвращает модифцированный массив с описанием элемента управления по его коду. Берет название и настройки |
528
|
|
|
* из админ-интерфейса, если они не заданы — используются значения по умолчанию. |
529
|
|
|
* |
530
|
|
|
* Если элемент управления описан в админ-интерфейсе, то дефолтные настройки и описанные в классе интерфейса |
531
|
|
|
* будут совмещены (смержены). |
532
|
|
|
* |
533
|
|
|
* @param $code |
534
|
|
|
* @param $params |
535
|
|
|
* @param array $keys |
536
|
|
|
* |
537
|
|
|
* @return array|bool |
538
|
|
|
*/ |
539
|
|
|
protected function getButton($code, $params, $keys = array('name', 'TEXT')) |
540
|
|
|
{ |
541
|
|
|
$interfaceClass = static::getInterfaceClass(); |
542
|
|
|
$interfaceSettings = static::getInterfaceSettings(); |
543
|
|
|
|
544
|
|
|
if ($interfaceClass && !empty($interfaceSettings['BUTTONS'])) { |
|
|
|
|
545
|
|
|
$buttons = $interfaceSettings['BUTTONS']; |
546
|
|
|
|
547
|
|
|
if (is_array($buttons) && isset($buttons[$code])) { |
548
|
|
|
if ($buttons[$code]['VISIBLE'] == 'N') { |
549
|
|
|
return false; |
550
|
|
|
} |
551
|
|
|
$params = array_merge($params, $buttons[$code]); |
552
|
|
|
|
553
|
|
|
return $params; |
554
|
|
|
} |
555
|
|
|
} |
556
|
|
|
|
557
|
|
|
$text = Loc::getMessage('DIGITALWAND_ADMIN_HELPER_' . $code); |
558
|
|
|
|
559
|
|
|
foreach ($keys as $key) { |
560
|
|
|
$params[$key] = $text; |
561
|
|
|
} |
562
|
|
|
|
563
|
|
|
return $params; |
564
|
|
|
} |
565
|
|
|
|
566
|
|
|
/** |
567
|
|
|
* Возвращает список полей интерфейса. |
568
|
|
|
* |
569
|
|
|
* @see AdminBaseHelper::setInterfaceSettings() |
570
|
|
|
* |
571
|
|
|
* @return array |
572
|
|
|
* |
573
|
|
|
* @api |
574
|
|
|
*/ |
575
|
|
|
public function getFields() |
576
|
|
|
{ |
577
|
|
|
return $this->fields; |
578
|
|
|
} |
579
|
|
|
|
580
|
|
|
/** |
581
|
|
|
* Окончательно выводит административную страницу. |
582
|
|
|
*/ |
583
|
|
|
abstract public function show(); |
584
|
|
|
|
585
|
|
|
/** |
586
|
|
|
* Получает название таблицы используемой модели. |
587
|
|
|
* |
588
|
|
|
* @return mixed |
589
|
|
|
*/ |
590
|
|
|
public function table() |
591
|
|
|
{ |
592
|
|
|
/** |
593
|
|
|
* @var DataManager $className |
594
|
|
|
*/ |
595
|
|
|
$className = static::getModel(); |
596
|
|
|
|
597
|
|
|
return $className::getTableName(); |
598
|
|
|
} |
599
|
|
|
|
600
|
|
|
/** |
601
|
|
|
* Возвращает первичный ключ таблицы используемой модели |
602
|
|
|
* Для HL-инфоблоков битрикс - всегда ID. Но может поменяться для какой-либо другой сущности. |
603
|
|
|
* @return string |
604
|
|
|
* @api |
605
|
|
|
*/ |
606
|
|
|
public function pk() |
607
|
|
|
{ |
608
|
|
|
return 'ID'; |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
/** |
612
|
|
|
* Возвращает значение первичного ключа таблицы используемой модели |
613
|
|
|
* @return array|int|null |
614
|
|
|
* |
615
|
|
|
* @api |
616
|
|
|
*/ |
617
|
|
|
public function getPk() |
|
|
|
|
618
|
|
|
{ |
619
|
|
|
return isset($_REQUEST['FIELDS'][$this->pk()]) ? $_REQUEST['FIELDS'][$this->pk()] : $_REQUEST[$this->pk()]; |
620
|
|
|
} |
621
|
|
|
|
622
|
|
|
/** |
623
|
|
|
* Возвращает первичный ключ таблицы используемой модели разделов. Для HL-инфоблоков битрикс - всегда ID. |
624
|
|
|
* Но может поменяться для какой-либо другой сущности. |
625
|
|
|
* |
626
|
|
|
* @return string |
627
|
|
|
* |
628
|
|
|
* @api |
629
|
|
|
*/ |
630
|
|
|
public function sectionPk() |
631
|
|
|
{ |
632
|
|
|
return 'ID'; |
633
|
|
|
} |
634
|
|
|
|
635
|
|
|
/** |
636
|
|
|
* Устанавливает заголовок раздела в админке. |
637
|
|
|
* |
638
|
|
|
* @param string $title |
639
|
|
|
* |
640
|
|
|
* @api |
641
|
|
|
*/ |
642
|
|
|
public function setTitle($title) |
643
|
|
|
{ |
644
|
|
|
$this->app->SetTitle($title); |
645
|
|
|
} |
646
|
|
|
|
647
|
|
|
/** |
648
|
|
|
* Функция для обработки дополнительных операций над элементами в админке. Как правило, должно оканчиваться |
649
|
|
|
* LocalRedirect после внесения изменений. |
650
|
|
|
* |
651
|
|
|
* @param string $action Название действия. |
652
|
|
|
* @param null|int $id ID элемента. |
653
|
|
|
* |
654
|
|
|
* @api |
655
|
|
|
*/ |
656
|
|
|
protected function customActions($action, $id = null) |
657
|
|
|
{ |
658
|
|
|
return; |
659
|
|
|
} |
660
|
|
|
|
661
|
|
|
/** |
662
|
|
|
* Выполняется проверка прав на доступ к сущности. |
663
|
|
|
* |
664
|
|
|
* @return bool |
665
|
|
|
* |
666
|
|
|
* @api |
667
|
|
|
*/ |
668
|
|
|
protected function hasRights() |
669
|
|
|
{ |
670
|
|
|
return true; |
671
|
|
|
} |
672
|
|
|
|
673
|
|
|
/** |
674
|
|
|
* Выполняется проверка прав на выполнение операций чтения элементов. |
675
|
|
|
* |
676
|
|
|
* @return bool |
677
|
|
|
* |
678
|
|
|
* @api |
679
|
|
|
*/ |
680
|
|
|
protected function hasReadRights() |
681
|
|
|
{ |
682
|
|
|
return true; |
683
|
|
|
} |
684
|
|
|
|
685
|
|
|
/** |
686
|
|
|
* Выполняется проверка прав на выполнение операций редактирования элементов. |
687
|
|
|
* |
688
|
|
|
* @return bool |
689
|
|
|
* |
690
|
|
|
* @api |
691
|
|
|
*/ |
692
|
|
|
protected function hasWriteRights() |
693
|
|
|
{ |
694
|
|
|
return true; |
695
|
|
|
} |
696
|
|
|
|
697
|
|
|
/** |
698
|
|
|
* Проверка прав на изменение определенного элемента. |
699
|
|
|
* |
700
|
|
|
* @param array $element Массив данных элемента. |
701
|
|
|
* |
702
|
|
|
* @return bool |
703
|
|
|
* |
704
|
|
|
* @api |
705
|
|
|
*/ |
706
|
|
|
protected function hasWriteRightsElement($element = array()) |
|
|
|
|
707
|
|
|
{ |
708
|
|
|
if (!$this->hasWriteRights()) { |
709
|
|
|
return false; |
710
|
|
|
} |
711
|
|
|
|
712
|
|
|
return true; |
713
|
|
|
} |
714
|
|
|
|
715
|
|
|
/** |
716
|
|
|
* Выполняется проверка прав на выполнение опреаций удаления элементов. |
717
|
|
|
* |
718
|
|
|
* @return bool |
719
|
|
|
* |
720
|
|
|
* @api |
721
|
|
|
*/ |
722
|
|
|
protected function hasDeleteRights() |
723
|
|
|
{ |
724
|
|
|
return true; |
725
|
|
|
} |
726
|
|
|
|
727
|
|
|
/** |
728
|
|
|
* Выводит сообщения об ошибках. |
729
|
|
|
* |
730
|
|
|
* @internal |
731
|
|
|
*/ |
732
|
|
|
protected function showMessages() |
733
|
|
|
{ |
734
|
|
|
$allErrors = $this->getErrors(); |
735
|
|
|
$notes = $this->getNotes(); |
736
|
|
|
|
737
|
|
|
if (!empty($allErrors)) { |
738
|
|
|
$errorList[] = implode("\n", $allErrors); |
|
|
|
|
739
|
|
|
} |
740
|
|
|
if ($e = $this->getLastException()) { |
741
|
|
|
$errorList[] = trim($e->GetString()); |
|
|
|
|
742
|
|
|
} |
743
|
|
|
|
744
|
|
|
if (!empty($errorList)) { |
745
|
|
|
$errorText = implode("\n\n", $errorList); |
746
|
|
|
\CAdminMessage::ShowOldStyleError($errorText); |
747
|
|
|
} |
748
|
|
|
else { |
749
|
|
|
if (!empty($notes)) { |
750
|
|
|
$noteText = implode("\n\n", $notes); |
751
|
|
|
\CAdminMessage::ShowNote($noteText); |
752
|
|
|
} |
753
|
|
|
} |
754
|
|
|
} |
755
|
|
|
|
756
|
|
|
/** |
757
|
|
|
* @return bool|\CApplicationException |
758
|
|
|
* |
759
|
|
|
* @internal |
760
|
|
|
*/ |
761
|
|
View Code Duplication |
protected function getLastException() |
|
|
|
|
762
|
|
|
{ |
763
|
|
|
if (isset($_SESSION['APPLICATION_EXCEPTION']) AND !empty($_SESSION['APPLICATION_EXCEPTION'])) { |
|
|
|
|
764
|
|
|
/** @var CApplicationException $e */ |
765
|
|
|
$e = $_SESSION['APPLICATION_EXCEPTION']; |
766
|
|
|
unset($_SESSION['APPLICATION_EXCEPTION']); |
767
|
|
|
|
768
|
|
|
return $e; |
769
|
|
|
} |
770
|
|
|
else { |
771
|
|
|
return false; |
772
|
|
|
} |
773
|
|
|
} |
774
|
|
|
|
775
|
|
|
/** |
776
|
|
|
* @param $e |
777
|
|
|
*/ |
778
|
|
|
protected function setAppException($e) |
|
|
|
|
779
|
|
|
{ |
780
|
|
|
$_SESSION['APPLICATION_EXCEPTION'] = $e; |
781
|
|
|
} |
782
|
|
|
|
783
|
|
|
/** |
784
|
|
|
* Добавляет ошибку или массив ошибок для показа пользователю. |
785
|
|
|
* |
786
|
|
|
* @param array|string $errors |
787
|
|
|
* |
788
|
|
|
* @api |
789
|
|
|
*/ |
790
|
|
View Code Duplication |
public function addErrors($errors) |
|
|
|
|
791
|
|
|
{ |
792
|
|
|
if (!is_array($errors)) { |
793
|
|
|
$errors = array($errors); |
794
|
|
|
} |
795
|
|
|
|
796
|
|
|
if (isset($_SESSION['ELEMENT_SAVE_ERRORS']) AND !empty($_SESSION['ELEMENT_SAVE_ERRORS'])) { |
|
|
|
|
797
|
|
|
$_SESSION['ELEMENT_SAVE_ERRORS'] = array_merge($_SESSION['ELEMENT_SAVE_ERRORS'], $errors); |
798
|
|
|
} |
799
|
|
|
else { |
800
|
|
|
$_SESSION['ELEMENT_SAVE_ERRORS'] = $errors; |
801
|
|
|
} |
802
|
|
|
} |
803
|
|
|
|
804
|
|
|
/** |
805
|
|
|
* Добавляет уведомление или список уведомлений для показа пользователю. |
806
|
|
|
* |
807
|
|
|
* @param array|string $notes |
808
|
|
|
* |
809
|
|
|
* @api |
810
|
|
|
*/ |
811
|
|
View Code Duplication |
public function addNotes($notes) |
|
|
|
|
812
|
|
|
{ |
813
|
|
|
if (!is_array($notes)) { |
814
|
|
|
$notes = array($notes); |
815
|
|
|
} |
816
|
|
|
|
817
|
|
|
if (isset($_SESSION['ELEMENT_SAVE_NOTES']) AND !empty($_SESSION['ELEMENT_SAVE_NOTES'])) { |
|
|
|
|
818
|
|
|
$_SESSION['ELEMENT_SAVE_NOTES'] = array_merge($_SESSION['ELEMENT_SAVE_NOTES'], |
819
|
|
|
$notes); |
820
|
|
|
} |
821
|
|
|
else { |
822
|
|
|
$_SESSION['ELEMENT_SAVE_NOTES'] = $notes; |
823
|
|
|
} |
824
|
|
|
} |
825
|
|
|
|
826
|
|
|
/** |
827
|
|
|
* @return bool|array |
828
|
|
|
* |
829
|
|
|
* @api |
830
|
|
|
*/ |
831
|
|
View Code Duplication |
protected function getErrors() |
|
|
|
|
832
|
|
|
{ |
833
|
|
|
if (isset($_SESSION['ELEMENT_SAVE_ERRORS']) AND !empty($_SESSION['ELEMENT_SAVE_ERRORS'])) { |
|
|
|
|
834
|
|
|
$errors = $_SESSION['ELEMENT_SAVE_ERRORS']; |
835
|
|
|
unset($_SESSION['ELEMENT_SAVE_ERRORS']); |
836
|
|
|
|
837
|
|
|
return $errors; |
838
|
|
|
} |
839
|
|
|
else { |
840
|
|
|
return false; |
841
|
|
|
} |
842
|
|
|
} |
843
|
|
|
|
844
|
|
|
/** |
845
|
|
|
* @return bool |
846
|
|
|
* |
847
|
|
|
* @api |
848
|
|
|
*/ |
849
|
|
View Code Duplication |
protected function getNotes() |
|
|
|
|
850
|
|
|
{ |
851
|
|
|
if (isset($_SESSION['ELEMENT_SAVE_NOTES']) AND !empty($_SESSION['ELEMENT_SAVE_NOTES'])) { |
|
|
|
|
852
|
|
|
$notes = $_SESSION['ELEMENT_SAVE_NOTES']; |
853
|
|
|
unset($_SESSION['ELEMENT_SAVE_NOTES']); |
854
|
|
|
|
855
|
|
|
return $notes; |
856
|
|
|
} |
857
|
|
|
else { |
858
|
|
|
return false; |
859
|
|
|
} |
860
|
|
|
} |
861
|
|
|
|
862
|
|
|
/** |
863
|
|
|
* Возвращает класс хелпера нужного типа из всех зарегистрированных хелперов в модуле и находящихся |
864
|
|
|
* в том же неймспейсе что класс хелпера из которого вызван этот метод |
865
|
|
|
* |
866
|
|
|
* Под типом понимается ближайший родитель из модуля AdminHelper. |
867
|
|
|
* |
868
|
|
|
* Например если нам нужно получить ListHelper для формирования ссылки на список из EditHelper, |
869
|
|
|
* то это будет вглядеть так $listHelperClass = static::getHelperClass(AdminListHelper::getClass()) |
870
|
|
|
* |
871
|
|
|
* @param $class |
872
|
|
|
* |
873
|
|
|
* @return string|bool |
874
|
|
|
*/ |
875
|
|
|
public function getHelperClass($class) |
876
|
|
|
{ |
877
|
|
|
$interfaceSettings = self::$interfaceSettings[static::getModule()]; |
878
|
|
|
|
879
|
|
|
foreach ($interfaceSettings as $viewName => $settings) { |
880
|
|
|
$parentClasses = class_parents($settings['helper']); |
881
|
|
|
array_pop($parentClasses); // AdminBaseHelper |
882
|
|
|
|
883
|
|
|
$parentClass = array_pop($parentClasses); |
884
|
|
|
$thirdClass = array_pop($parentClasses); |
885
|
|
|
|
886
|
|
|
if (in_array($thirdClass, array(AdminSectionListHelper::className(), AdminSectionEditHelper::className()))) { |
887
|
|
|
$parentClass = $thirdClass; |
888
|
|
|
} |
889
|
|
|
|
890
|
|
|
if ($parentClass == $class && class_exists($settings['helper'])) { |
891
|
|
|
$helperClassParts = explode('\\', $settings['helper']); |
892
|
|
|
array_pop($helperClassParts); |
893
|
|
|
$helperNamespace = implode('\\', $helperClassParts); |
894
|
|
|
|
895
|
|
|
$сlassParts = explode('\\', get_called_class()); |
896
|
|
|
array_pop($сlassParts); |
897
|
|
|
$classNamespace = implode('\\', $сlassParts); |
898
|
|
|
|
899
|
|
|
if ($helperNamespace == $classNamespace) { |
900
|
|
|
return $settings['helper']; |
901
|
|
|
} |
902
|
|
|
} |
903
|
|
|
} |
904
|
|
|
|
905
|
|
|
return false; |
906
|
|
|
} |
907
|
|
|
|
908
|
|
|
/** |
909
|
|
|
* Возвращает относительный namespace до хелперов в виде URL параметра. |
910
|
|
|
* |
911
|
|
|
* @return string |
912
|
|
|
*/ |
913
|
|
|
public static function getEntityCode() |
914
|
|
|
{ |
915
|
|
|
$namespaceParts = explode('\\', get_called_class()); |
916
|
|
|
array_pop($namespaceParts); |
917
|
|
|
array_shift($namespaceParts); |
918
|
|
|
array_shift($namespaceParts); |
919
|
|
|
|
920
|
|
|
if (end($namespaceParts) == 'AdminInterface') { |
921
|
|
|
array_pop($namespaceParts); |
922
|
|
|
} |
923
|
|
|
|
924
|
|
|
return str_replace( |
925
|
|
|
'\\', |
926
|
|
|
'_', |
927
|
|
|
implode( |
928
|
|
|
'\\', |
929
|
|
|
array_map('lcfirst', $namespaceParts) |
930
|
|
|
) |
931
|
|
|
); |
932
|
|
|
} |
933
|
|
|
|
934
|
|
|
/** |
935
|
|
|
* Возвращает URL страницы редактирования класса данного представления. |
936
|
|
|
* |
937
|
|
|
* @param array $params |
938
|
|
|
* |
939
|
|
|
* @return string |
940
|
|
|
* |
941
|
|
|
* @api |
942
|
|
|
*/ |
943
|
|
View Code Duplication |
public static function getEditPageURL($params = array()) |
|
|
|
|
944
|
|
|
{ |
945
|
|
|
$editHelperClass = str_replace('List', 'Edit', get_called_class()); |
946
|
|
|
if (empty(static::$editViewName) && class_exists($editHelperClass)) { |
947
|
|
|
return $editHelperClass::getViewURL($editHelperClass::getViewName(), static::$editPageUrl, $params); |
948
|
|
|
} |
949
|
|
|
else { |
950
|
|
|
return static::getViewURL(static::$editViewName, static::$editPageUrl, $params); |
951
|
|
|
} |
952
|
|
|
} |
953
|
|
|
|
954
|
|
|
/** |
955
|
|
|
* Возвращает URL страницы редактирования класса данного представления. |
956
|
|
|
* |
957
|
|
|
* @param array $params |
958
|
|
|
* |
959
|
|
|
* @return string |
960
|
|
|
* |
961
|
|
|
* @api |
962
|
|
|
*/ |
963
|
|
View Code Duplication |
public static function getSectionsEditPageURL($params = array()) |
|
|
|
|
964
|
|
|
{ |
965
|
|
|
$sectionEditHelperClass = str_replace('List', 'SectionsEdit', get_called_class()); |
966
|
|
|
|
967
|
|
|
if (empty(static::$sectionsEditViewName) && class_exists($sectionEditHelperClass)) { |
968
|
|
|
return $sectionEditHelperClass::getViewURL($sectionEditHelperClass::getViewName(), static::$sectionsEditPageUrl, $params); |
969
|
|
|
} |
970
|
|
|
else { |
971
|
|
|
return static::getViewURL(static::$sectionsEditViewName, static::$sectionsEditPageUrl, $params); |
972
|
|
|
} |
973
|
|
|
} |
974
|
|
|
|
975
|
|
|
/** |
976
|
|
|
* Возвращает URL страницы списка класса данного представления. |
977
|
|
|
* |
978
|
|
|
* @param array $params |
979
|
|
|
* |
980
|
|
|
* @return string |
981
|
|
|
* |
982
|
|
|
* @api |
983
|
|
|
*/ |
984
|
|
View Code Duplication |
public static function getListPageURL($params = array()) |
|
|
|
|
985
|
|
|
{ |
986
|
|
|
$listHelperClass = str_replace('Edit', 'List', get_called_class()); |
987
|
|
|
|
988
|
|
|
if (empty(static::$listViewName) && class_exists($listHelperClass)) { |
989
|
|
|
return $listHelperClass::getViewURL($listHelperClass::getViewName(), static::$listPageUrl, $params); |
990
|
|
|
} |
991
|
|
|
else { |
992
|
|
|
return static::getViewURL(static::$listViewName, static::$listPageUrl, $params); |
993
|
|
|
} |
994
|
|
|
} |
995
|
|
|
|
996
|
|
|
/** |
997
|
|
|
* Получает URL для указанного представления |
998
|
|
|
* |
999
|
|
|
* @param string $viewName Название представления. |
1000
|
|
|
* @param string $defaultURL Позволяет указать URL напрямую. Если указано, то будет использовано это значение. |
1001
|
|
|
* @param array $params Дополнительные query-параметры в URL. |
1002
|
|
|
* |
1003
|
|
|
* @return string |
1004
|
|
|
* |
1005
|
|
|
* @internal |
1006
|
|
|
*/ |
1007
|
|
|
public static function getViewURL($viewName, $defaultURL, $params = array()) |
1008
|
|
|
{ |
1009
|
|
|
$params['entity'] = static::getEntityCode(); |
1010
|
|
|
|
1011
|
|
|
if (isset($defaultURL)) { |
1012
|
|
|
$url = $defaultURL . "?lang=" . LANGUAGE_ID; |
1013
|
|
|
} |
1014
|
|
|
else { |
1015
|
|
|
$url = static::getRouterURL() . '?lang=' . LANGUAGE_ID . '&module=' . static::getModule() . '&view=' . $viewName; |
1016
|
|
|
} |
1017
|
|
|
|
1018
|
|
|
if (!empty($params)) { |
1019
|
|
|
unset($params['lang']); |
1020
|
|
|
unset($params['module']); |
1021
|
|
|
unset($params['view']); |
1022
|
|
|
|
1023
|
|
|
$query = http_build_query($params); |
1024
|
|
|
$url .= '&' . $query; |
1025
|
|
|
} |
1026
|
|
|
|
1027
|
|
|
return $url; |
1028
|
|
|
} |
1029
|
|
|
|
1030
|
|
|
/** |
1031
|
|
|
* Возвращает адрес обработчика запросов к админ. интерфейсу. |
1032
|
|
|
* |
1033
|
|
|
* @return string |
1034
|
|
|
* |
1035
|
|
|
* @api |
1036
|
|
|
*/ |
1037
|
|
|
public static function getRouterURL() |
1038
|
|
|
{ |
1039
|
|
|
return static::$routerUrl; |
1040
|
|
|
} |
1041
|
|
|
|
1042
|
|
|
/** |
1043
|
|
|
* Возвращает URL страницы с хелпером. Как правило, метод вызывается при генерации административного |
1044
|
|
|
* меню (`menu.php`). |
1045
|
|
|
* |
1046
|
|
|
* @param array $params Дополнительные GET-параметры для подстановки в URL. |
1047
|
|
|
* |
1048
|
|
|
* @return string |
1049
|
|
|
*/ |
1050
|
|
|
public static function getUrl(array $params = array()) |
1051
|
|
|
{ |
1052
|
|
|
return static::getViewURL(static::getViewName(), null, $params); |
1053
|
|
|
} |
1054
|
|
|
|
1055
|
|
|
/** |
1056
|
|
|
* Получает виджет для текущего поля, выполняет базовую инициализацию. |
1057
|
|
|
* |
1058
|
|
|
* @param string $code Ключ поля для данного виджета (должен быть в массиве $data). |
1059
|
|
|
* @param array $data Данные объекта в виде массива. |
1060
|
|
|
* |
1061
|
|
|
* @return bool|\DigitalWand\AdminHelper\Widget\HelperWidget |
1062
|
|
|
* |
1063
|
|
|
* @throws \DigitalWand\AdminHelper\Helper\Exception |
1064
|
|
|
* |
1065
|
|
|
* @internal |
1066
|
|
|
*/ |
1067
|
|
|
public function createWidgetForField($code, &$data = array()) |
1068
|
|
|
{ |
1069
|
|
View Code Duplication |
if (!isset($this->fields[$code]['WIDGET'])) { |
|
|
|
|
1070
|
|
|
$error = str_replace('#CODE#', $code, 'Can\'t create widget for the code "#CODE#"'); |
1071
|
|
|
throw new Exception($error, Exception::CODE_NO_WIDGET); |
1072
|
|
|
} |
1073
|
|
|
|
1074
|
|
|
/** @var HelperWidget $widget */ |
1075
|
|
|
$widget = $this->fields[$code]['WIDGET']; |
1076
|
|
|
|
1077
|
|
|
$widget->setHelper($this); |
1078
|
|
|
$widget->setCode($code); |
1079
|
|
|
$widget->setData($data); |
1080
|
|
|
$widget->setEntityName($this->getModel()); |
|
|
|
|
1081
|
|
|
|
1082
|
|
|
$this->onCreateWidgetForField($widget, $data); |
1083
|
|
|
|
1084
|
|
|
if (!$this->hasWriteRightsElement($data)) { |
1085
|
|
|
$widget->setSetting('READONLY', true); |
1086
|
|
|
} |
1087
|
|
|
|
1088
|
|
|
return $widget; |
1089
|
|
|
} |
1090
|
|
|
|
1091
|
|
|
/** |
1092
|
|
|
* Метод вызывается при создании виджета для текущего поля. Может быть использован для изменения настроек виджета |
1093
|
|
|
* на основе передаваемых данных. |
1094
|
|
|
* |
1095
|
|
|
* @param \DigitalWand\AdminHelper\Widget\HelperWidget $widget |
1096
|
|
|
* @param array $data |
1097
|
|
|
*/ |
1098
|
|
|
protected function onCreateWidgetForField(&$widget, $data = array()) |
|
|
|
|
1099
|
|
|
{ |
1100
|
|
|
} |
1101
|
|
|
|
1102
|
|
|
/** |
1103
|
|
|
* Если класс не объявлен, то битрикс генерирует новый класс в рантайме. Если класс уже есть, то возвращаем имя |
1104
|
|
|
* как есть. |
1105
|
|
|
* |
1106
|
|
|
* @param $className |
1107
|
|
|
* @return \Bitrix\Highloadblock\DataManager |
1108
|
|
|
* |
1109
|
|
|
* @throws \Bitrix\Main\ArgumentException |
1110
|
|
|
* @throws \Bitrix\Main\SystemException |
1111
|
|
|
* @throws Exception |
1112
|
|
|
*/ |
1113
|
|
|
public static function getHLEntity($className) |
1114
|
|
|
{ |
1115
|
|
|
if (!class_exists($className)) { |
1116
|
|
|
$info = static::getHLEntityInfo($className); |
1117
|
|
|
|
1118
|
|
|
if ($info) { |
1119
|
|
|
$entity = HL\HighloadBlockTable::compileEntity($info); |
1120
|
|
|
|
1121
|
|
|
return $entity->getDataClass(); |
1122
|
|
|
} |
1123
|
|
|
else { |
1124
|
|
|
$error = Loc::getMessage('DIGITALWAND_ADMIN_HELPER_GETMODEL_EXCEPTION', array('#CLASS#' => $className)); |
1125
|
|
|
$exception = new Exception($error, Exception::CODE_NO_HL_ENTITY_INFORMATION); |
1126
|
|
|
|
1127
|
|
|
throw $exception; |
1128
|
|
|
} |
1129
|
|
|
} |
1130
|
|
|
|
1131
|
|
|
return $className; |
1132
|
|
|
} |
1133
|
|
|
|
1134
|
|
|
/** |
1135
|
|
|
* Получает запись из БД с информацией об HL. |
1136
|
|
|
* |
1137
|
|
|
* @param string $className Название класса, обязательно без Table в конце и без указания неймспейса. |
1138
|
|
|
* |
1139
|
|
|
* @return array|false |
1140
|
|
|
* |
1141
|
|
|
* @throws \Bitrix\Main\ArgumentException |
1142
|
|
|
*/ |
1143
|
|
|
public static function getHLEntityInfo($className) |
1144
|
|
|
{ |
1145
|
|
|
$className = str_replace('\\', '', $className); |
1146
|
|
|
$pos = strripos($className, 'Table', -5); |
1147
|
|
|
|
1148
|
|
|
if ($pos !== false) { |
1149
|
|
|
$className = substr($className, 0, $pos); |
1150
|
|
|
} |
1151
|
|
|
|
1152
|
|
|
$parameters = array( |
1153
|
|
|
'filter' => array( |
1154
|
|
|
'NAME' => $className, |
1155
|
|
|
), |
1156
|
|
|
'limit' => 1 |
1157
|
|
|
); |
1158
|
|
|
|
1159
|
|
|
return HL\HighloadBlockTable::getList($parameters)->fetch(); |
1160
|
|
|
} |
1161
|
|
|
|
1162
|
|
|
/** |
1163
|
|
|
* Отобразить страницу 404 ошибка |
1164
|
|
|
*/ |
1165
|
|
|
protected function show404() |
|
|
|
|
1166
|
|
|
{ |
1167
|
|
|
// инициализация глобальных переменных, необходимых для вывода страницы административного раздела в |
1168
|
|
|
// текущей области видимости |
1169
|
|
|
global $APPLICATION, $adminPage, $adminMenu, $USER; |
|
|
|
|
1170
|
|
|
\CHTTP::SetStatus(404); |
1171
|
|
|
include $_SERVER['DOCUMENT_ROOT'] . BX_ROOT . '/admin/404.php'; |
1172
|
|
|
die(); |
|
|
|
|
1173
|
|
|
} |
1174
|
|
|
|
1175
|
|
|
/** |
1176
|
|
|
* Выставляет текущий контекст исполнения. |
1177
|
|
|
* |
1178
|
|
|
* @param $context |
1179
|
|
|
* |
1180
|
|
|
* @see $context |
1181
|
|
|
*/ |
1182
|
|
|
protected function setContext($context) |
1183
|
|
|
{ |
1184
|
|
|
$this->context = $context; |
1185
|
|
|
} |
1186
|
|
|
|
1187
|
|
|
public function getContext() |
1188
|
|
|
{ |
1189
|
|
|
return $this->context; |
1190
|
|
|
} |
1191
|
|
|
|
1192
|
|
|
public static function className() |
1193
|
|
|
{ |
1194
|
|
|
return get_called_class(); |
1195
|
|
|
} |
1196
|
|
|
} |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.