AdminBaseHelper::getGlobalInterfaceSettings()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 2
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 94 and the first side effect is on line 15.

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.

Loading history...
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 = "")
0 ignored issues
show
Unused Code introduced by
The parameter $module is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
274
	{
275
		global $APPLICATION;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
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'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $interfaceClass of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
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()
0 ignored issues
show
Coding Style introduced by
getPk uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
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())
0 ignored issues
show
Unused Code introduced by
The parameter $element is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$errorList was never initialized. Although not strictly required by PHP, it is generally a good practice to add $errorList = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
739
		}
740
		if ($e = $this->getLastException()) {
741
			$errorList[] = trim($e->GetString());
0 ignored issues
show
Bug introduced by
The variable $errorList does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
getLastException uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
762
	{
763
		if (isset($_SESSION['APPLICATION_EXCEPTION']) AND !empty($_SESSION['APPLICATION_EXCEPTION'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
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)
0 ignored issues
show
Coding Style introduced by
setAppException uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
addErrors uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
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'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
addNotes uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
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'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
getErrors uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
832
	{
833
		if (isset($_SESSION['ELEMENT_SAVE_ERRORS']) AND !empty($_SESSION['ELEMENT_SAVE_ERRORS'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
getNotes uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
850
	{
851
		if (isset($_SESSION['ELEMENT_SAVE_NOTES']) AND !empty($_SESSION['ELEMENT_SAVE_NOTES'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
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())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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());
0 ignored issues
show
Documentation introduced by
$this->getModel() is of type object<Bitrix\Highloadblock\DataManager>|null, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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())
0 ignored issues
show
Unused Code introduced by
The parameter $widget is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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()
0 ignored issues
show
Coding Style introduced by
show404 uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1166
	{
1167
		// инициализация глобальных переменных, необходимых для вывода страницы административного раздела в
1168
		// текущей области видимости
1169
		global $APPLICATION, $adminPage, $adminMenu, $USER;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1170
		\CHTTP::SetStatus(404);
1171
		include $_SERVER['DOCUMENT_ROOT'] . BX_ROOT . '/admin/404.php';
1172
		die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method show404() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
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
}