Skip to content

Commit 8ce82ed

Browse files
add CheckboxMenuWithInput widget for permission management
1 parent f188bca commit 8ce82ed

File tree

4 files changed

+256
-3
lines changed

4 files changed

+256
-3
lines changed

src/models/Roles.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Yii;
66
use ZakharovAndrew\user\Module;
77
use \yii\helpers\ArrayHelper;
8+
use yii\helpers\Json;
89

910
/**
1011
* This is the model class for table "roles".
@@ -86,6 +87,54 @@ public static function getRolesByUserId($user_id)
8687
}, 10);
8788
}
8889

90+
public static function getAllowedParametersList()
91+
{
92+
$items = [];
93+
$controllersAccessList = Yii::$app->getModule('user')->controllersAccessList;
94+
95+
foreach ($controllersAccessList as $controller_id => $params) {
96+
if (is_string($controller_id)) {
97+
$submenu = [];
98+
// find submenu
99+
foreach ($params as $item_id => $item) {
100+
$submenu = array_merge($submenu, static::getSubItem($item_id, $item));
101+
}
102+
// don't create submenu
103+
if (count($submenu) == 1) {
104+
$items = array_merge($items, $submenu);
105+
} else if (count($submenu) > 0) {
106+
$items[] = ['label' => $controller_id, 'items' => $submenu];
107+
}
108+
} else {
109+
$items = array_merge($items, static::getSubItem($controller_id, $params));
110+
}
111+
}
112+
113+
return $items;
114+
}
115+
116+
public static function getSubItem($controller_id, $items)
117+
{
118+
$menu_items = [];
119+
120+
// Processing each menu item
121+
foreach ($items as $link => $item) {
122+
$url = $link;
123+
$label = $item;
124+
125+
if (is_array($item) && is_int($link)) {
126+
$label = $item['label'];
127+
} else if (is_array($item)) {
128+
$menu_items[] = ['label' => $link, 'items' => static::getSubItem($controller_id, $item)];
129+
continue;
130+
}
131+
132+
$menu_items[] = ['label' => $label, 'id' => $controller_id];
133+
}
134+
135+
return $menu_items;
136+
}
137+
89138
public function getParametersList()
90139
{
91140
return json_decode($this->parameters) ?? [];
@@ -130,4 +179,25 @@ public function getSubjects()
130179

131180
return [];
132181
}
182+
183+
// Если нужно преобразовать JSON в массив при загрузке
184+
public function afterFind()
185+
{
186+
parent::afterFind();
187+
if ($this->parameters) {
188+
$this->parameters = Json::decode($this->parameters);
189+
}
190+
}
191+
192+
// Перед сохранением
193+
public function beforeSave($insert)
194+
{
195+
if (parent::beforeSave($insert)) {
196+
if (is_array($this->parameters)) {
197+
$this->parameters = Json::encode($this->parameters);
198+
}
199+
return true;
200+
}
201+
return false;
202+
}
133203
}

src/models/User.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public static function getAccessList($user_id)
162162
break;
163163
}
164164

165-
foreach ($role->getParametersList() as $controller_id => $actions) {
165+
foreach ($role->parameters as $controller_id => $actions) {
166166
if ($actions == '*') {
167167
$list[$controller_id] = '*';
168168
continue;

src/views/roles/_form.php

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
use yii\helpers\Html;
44
use yii\widgets\ActiveForm;
5+
use yii\helpers\Json;
56
use ZakharovAndrew\user\Module;
7+
use ZakharovAndrew\user\models\Roles;
68

79
use ZakharovAndrew\user\assets\UserAssets;
810

@@ -13,6 +15,47 @@
1315
/** @var yii\widgets\ActiveForm $form */
1416
?>
1517

18+
<style>
19+
.checkbox-input-menu .menu-item {
20+
display: flex;
21+
align-items: center;
22+
margin: 10px 0;
23+
padding: 8px;
24+
border-radius: 4px;
25+
background: #f5f8fa;
26+
}
27+
28+
.checkbox-input-menu .menu-checkbox {
29+
margin-right: 10px;
30+
}
31+
32+
.checkbox-input-menu .menu-input {
33+
margin-left: 10px;
34+
width: 100%;
35+
display: inline-block;
36+
background: #e4ecf1;
37+
}
38+
39+
.checkbox-input-menu .menu-label {
40+
margin-left: 5px;
41+
cursor: pointer;
42+
width: 280px;
43+
}
44+
45+
.checkbox-input-menu .menu-group {
46+
margin-bottom: 20px;
47+
border: 1px solid #eee;
48+
padding: 15px;
49+
border-radius: 5px;
50+
}
51+
52+
.checkbox-input-menu .group-title {
53+
margin-top: 0;
54+
color: #333;
55+
font-size: 1.1em;
56+
}
57+
</style>
58+
1659
<div class="roles-form">
1760

1861
<?php $form = ActiveForm::begin(); ?>
@@ -21,10 +64,19 @@
2164
<?= $form->field($model, 'title')->textInput(['maxlength' => true]) ?>
2265

2366
<?= $form->field($model, 'code')->textInput() ?>
67+
68+
<?= $form->field($model, 'function_to_get_all_subjects')->textInput(['maxlength' => true]) ?>
69+
70+
<label><?= Module::t('Parameters')?></label>
2471

25-
<?= $form->field($model, 'parameters')->textarea(['rows' => 3]) ?>
72+
<?= ZakharovAndrew\user\widgets\CheckboxMenuWithInput::widget([
73+
'menu' => Roles::getAllowedParametersList(),
74+
'model' => $model,
75+
'attribute' => 'parameters',
76+
'selectedData' => $model->parameters ?? []
77+
]) ?>
2678

27-
<?= $form->field($model, 'function_to_get_all_subjects')->textInput(['maxlength' => true]) ?>
79+
2880

2981
<?= $form->field($model, 'description')->textarea(['rows' => 6]) ?>
3082
</div>

src/widgets/CheckboxMenuWithInput.php

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<?php
2+
3+
namespace ZakharovAndrew\user\widgets;
4+
5+
use yii\base\Widget;
6+
use yii\helpers\Html;
7+
use yii\helpers\Json;
8+
9+
class CheckboxMenuWithInput extends Widget
10+
{
11+
public $menu;
12+
public $model;
13+
public $attribute;
14+
public $selectedData = [];
15+
16+
public function run()
17+
{
18+
// Регистрируем JS для обработки связки чекбокс+поле
19+
$this->registerJs();
20+
return $this->renderMenu($this->menu);
21+
}
22+
23+
protected function renderMenu($items)
24+
{
25+
$html = '<div class="checkbox-input-menu">';
26+
foreach ($items as $item) {
27+
if (isset($item['items'])) {
28+
$html .= $this->renderGroup($item);
29+
} else {
30+
$html .= $this->renderItem($item);
31+
}
32+
}
33+
$html .= '</div>';
34+
35+
// Скрытое поле для хранения JSON
36+
$html .= Html::hiddenInput(
37+
$this->model ? "{$this->model->formName()}[{$this->attribute}]" : $this->attribute,
38+
Json::encode($this->selectedData),
39+
['class' => 'checkbox-input-json']
40+
);
41+
42+
return $html;
43+
}
44+
45+
protected function renderGroup($group)
46+
{
47+
$items = '';
48+
foreach ($group['items'] as $item) {
49+
$items .= $this->renderItem($item);
50+
}
51+
52+
return Html::tag('div',
53+
Html::tag('h3', Html::encode($group['label']), ['class' => 'group-title']) .
54+
Html::tag('div', $items, ['class' => 'group-items']),
55+
['class' => 'menu-group']
56+
);
57+
}
58+
59+
protected function renderItem($item)
60+
{
61+
$itemId = $item['id'];
62+
$isChecked = isset($this->selectedData[$itemId]);
63+
$textValue = $isChecked ? $this->selectedData[$itemId] : '';
64+
65+
return Html::tag('div',
66+
Html::checkbox(
67+
"checkbox_{$itemId}",
68+
$isChecked,
69+
[
70+
'value' => $itemId,
71+
'id' => "checkbox_{$itemId}",
72+
'class' => 'menu-checkbox',
73+
'data-item-id' => $itemId
74+
]
75+
) .
76+
Html::label($item['label'], "checkbox_{$itemId}", ['class' => 'menu-label']) .
77+
Html::input('text',
78+
"input_{$itemId}",
79+
$textValue,
80+
[
81+
'class' => 'menu-input form-control',
82+
'placeholder' => 'Введите значение',
83+
'data-item-id' => $itemId,
84+
'disabled' => !$isChecked
85+
]
86+
),
87+
88+
['class' => 'menu-item']
89+
);
90+
}
91+
92+
protected function registerJs()
93+
{
94+
$js = <<<JS
95+
$(document)
96+
.on('change', '.menu-checkbox', function() {
97+
var itemId = $(this).data('item-id');
98+
var input = $('.menu-input[data-item-id="' + itemId + '"]');
99+
input.prop('disabled', !this.checked);
100+
101+
if (!this.checked) {
102+
input.val('');
103+
}
104+
105+
updateJsonData();
106+
})
107+
.on('input', '.menu-input', function() {
108+
updateJsonData();
109+
});
110+
111+
function updateJsonData() {
112+
var result = {};
113+
114+
$('.menu-checkbox:checked').each(function() {
115+
var itemId = $(this).data('item-id');
116+
var inputValue = $('.menu-input[data-item-id="' + itemId + '"]').val();
117+
if (inputValue) {
118+
result[itemId] = inputValue;
119+
} else {
120+
result[itemId] = "*";
121+
}
122+
});
123+
124+
$('.checkbox-input-json').val(JSON.stringify(result));
125+
console.log(JSON.stringify(result));
126+
}
127+
JS;
128+
129+
$this->view->registerJs($js);
130+
}
131+
}

0 commit comments

Comments
 (0)