Skip to content

Commit f050cfa

Browse files
author
Eugene Tupikov
committed
Improvements
1 parent 800bd8b commit f050cfa

File tree

4 files changed

+228
-50
lines changed

4 files changed

+228
-50
lines changed

MultipleInput.php

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace unclead\widgets;
1010

1111
use Yii;
12+
use yii\base\InvalidConfigException;
1213
use yii\base\Model;
1314
use yii\widgets\InputWidget;
1415
use yii\helpers\Json;
@@ -26,38 +27,51 @@
2627
*/
2728
class MultipleInput extends InputWidget
2829
{
29-
const ACTION_ADD = 'plus';
30-
const ACTION_REMOVE = 'remove';
30+
const ACTION_ADD = 'plus';
31+
const ACTION_REMOVE = 'remove';
32+
3133
/**
3234
* @var ActiveRecord[]|array[] input data
3335
*/
3436
public $data = null;
37+
3538
/**
3639
* @var array columns configuration
3740
*/
3841
public $columns = [];
42+
3943
/**
4044
* @var integer inputs limit
4145
*/
4246
public $limit;
47+
4348
/**
4449
* @var string generated template, internal variable.
4550
*/
4651
protected $template;
52+
4753
/**
4854
* @var string
4955
*/
5056
protected $replacementKeys;
57+
58+
/**
59+
* Initialization.
60+
*
61+
* @throws \yii\base\InvalidConfigException
62+
*/
5163
public function init()
5264
{
5365
parent::init();
54-
// prepare data in case when need to render one column
66+
5567
if (is_null($this->data) && $this->model instanceof Model) {
5668
foreach ((array) $this->model->{$this->attribute} as $index => $value) {
57-
$this->data[$index][$this->attribute] = $value;
69+
$this->data[$index] = $value;
5870
}
5971
}
6072
}
73+
74+
6175
/**
6276
* Run widget.
6377
*/
@@ -177,6 +191,8 @@ private function getRowTemplate()
177191
'name' => $name,
178192
'value' => $value,
179193
]));
194+
} else {
195+
throw new InvalidConfigException("Invalid column type '$type'");
180196
}
181197
}
182198
$this->template .= Html::endTag('div');
@@ -206,11 +222,13 @@ private function getRowTemplate()
206222
}
207223
return $this->template;
208224
}
225+
209226
/**
210227
* Render row.
211228
*
212229
* @param integer $index
213230
* @param ActiveRecord|array $data
231+
* @throws InvalidConfigException
214232
*/
215233
private function renderRow($index, $data = null)
216234
{
@@ -219,11 +237,26 @@ private function renderRow($index, $data = null)
219237
$search = ['{index}', '{btn_action}', '{btn_type}'];
220238
$replace = [$index, $btnAction, $btnType];
221239
foreach ($this->getColumns() as $column) {
240+
if (!array_key_exists('name', $column)) {
241+
throw new InvalidConfigException("The 'name' option is required.");
242+
}
222243
$search[] = '{' . $column['name'] . '_value}';
223244
$replace[] = $this->prepareColumnValue($column, $data);
224245
}
225246
echo str_replace($search, $replace, $this->getRowTemplate());
226247
}
248+
249+
250+
private function getColumns()
251+
{
252+
if (empty($this->columns) && $this->hasModel()) {
253+
return [
254+
['name' => $this->attribute]
255+
];
256+
}
257+
return $this->columns;
258+
}
259+
227260
/**
228261
* @param $column
229262
* @param $data
@@ -241,28 +274,43 @@ private function prepareColumnValue($column, $data)
241274
$value = $data->{$column['name']};
242275
} elseif (is_array($data)) {
243276
$value = $data[$column['name']];
244-
} else {
277+
} elseif(is_string($data)) {
278+
$value = $data;
279+
}else {
245280
$value = ArrayHelper::getValue($column, 'defaultValue', '');
246281
}
247282
}
248283
return $value;
249284
}
285+
250286
/**
251287
* @param $name
252288
* @param string $index
253289
* @return string
254290
*/
255291
private function getElementName($name, $index = null)
256292
{
257-
$elementName = $this->getName();
258293
if ($index === null) {
259294
$index = '{index}';
260295
}
261-
$elementName .= count($this->getColumns()) > 1
262-
? '[' . $index . '][' . $name . ']'
263-
: '[' . $name . '][' . $index . ']';
264-
return $elementName;
296+
return $this->getAttributeName() . (
297+
count($this->columns) > 1
298+
? '[' . $index . '][' . $name . ']'
299+
: '[' . $name . '][' . $index . ']'
300+
);
265301
}
302+
303+
/**
304+
* @return string
305+
*/
306+
private function getAttributeName()
307+
{
308+
if ($this->hasModel()) {
309+
return empty($this->columns) ? $this->model->formName() : Html::getInputName($this->model, $this->attribute);
310+
}
311+
return $this->name;
312+
}
313+
266314
/**
267315
* @param $name
268316
* @return mixed
@@ -271,37 +319,17 @@ private function getElementId($name)
271319
{
272320
return $this->normalize($this->getElementName($name));
273321
}
322+
274323
/**
275324
* @param $name
276325
* @return mixed
277326
*/
278327
private function normalize($name) {
279328
return str_replace(['[]', '][', '[', ']', ' ', '.'], ['', '-', '-', '', '-', '-'], strtolower($name));
280329
}
330+
281331
/**
282-
* @return string
283-
*/
284-
private function getName()
285-
{
286-
if (empty($this->name) && $this->model instanceof Model) {
287-
return $this->model->formName();
288-
}
289-
return $this->name;
290-
}
291-
/**
292-
* @return array
293-
*/
294-
private function getColumns()
295-
{
296-
if (empty($this->columns) && $this->model instanceof Model && !empty($this->attribute)) {
297-
return [
298-
['name' => $this->attribute]
299-
];
300-
}
301-
return $this->columns;
302-
}
303-
/**
304-
* Регистрирует клиентский скрипт и опции.
332+
* Register script.
305333
*/
306334
public function registerClientScript()
307335
{

README.md

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,95 @@ to the require section of your `composer.json` file.
2727

2828
##Usage
2929

30-
For getting more detail read [documentation](docs/guide.md)
30+
In case when input has one column
3131

32-
##Examples
32+
```
33+
use unclead\widgets\MultipleInput;
34+
35+
<?= $form->field($model, 'emails')->widget(MultipleInput::className(), [
36+
'limit' => 5
37+
])
38+
->label(false);
39+
?>
40+
41+
```
42+
43+
In case when input has several columns
44+
45+
```
46+
47+
use unclead\widgets\MultipleInput;
48+
<?= $form->field($model, 'schedule')->widget(MultipleInput::className(), [
49+
'limit' => 4,
50+
'columns' => [
51+
[
52+
'name' => 'user_id',
53+
'type' => 'dropDownList',
54+
'title' => 'User',
55+
'defaultValue' => 1,
56+
'items' => [
57+
1 => 'User 1',
58+
2 => 'User 2'
59+
]
60+
],
61+
[
62+
'name' => 'day',
63+
'type' => 'dropDownList',
64+
'title' => 'Day',
65+
'value' => function($data) {
66+
return $data['day'];
67+
},
68+
'defaultValue' => 1,
69+
'items' => [
70+
'0' => 'Saturday',
71+
'1' => 'Monday'
72+
],
73+
'options' => [
74+
75+
]
76+
],
77+
[
78+
'name' => 'priority',
79+
'title' => 'Priority',
80+
'options' => [
81+
'class' => 'input-priority'
82+
]
83+
]
84+
]
85+
]);
86+
```
87+
88+
The configuration of widgets is described below
89+
90+
## Configuration
3391

92+
Widget support the following options that are additionally recognized over and above the configuration options in the InputWidget:
93+
94+
- `limit`: *integer*: rows limit
95+
- `columns` *array*: the row columns configuration where you can set the following properties:
96+
- `name` *string*: input name. Required options
97+
- `type` *string*: type of the input. If not set will default to `textInput`
98+
- `title` *string*: the column title
99+
- `value` *Closure: you can set it to an anonymous function with the following signature:
100+
101+
```php
102+
function($data) {
103+
return 'something';
104+
}
105+
```
106+
107+
- `defaultValue` *string*: default value of column's input,
108+
- `items` *array*: the items for drop down list if you set column type like as dropDownList
109+
- `options` *array*: the HTML options of column's input
110+
111+
##Examples
34112

35113
Widget supports several use cases:
36114

37115
- [Single column example](docs/single_column.md)
38116
- [Several columns example](docs/several_columns.md)
39117

40-
118+
You cad find source code of examples [here](./examples/)
41119
##License
42120

43121
**yii2-multiple-input** is released under the BSD 3-Clause License. See the bundled LICENSE.md for details.

examples/models/ExampleModel.php

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use yii\base\Model;
66
use yii\validators\EmailValidator;
77
use yii\validators\NumberValidator;
8+
use yii\validators\RequiredValidator;
89

910
/**
1011
* Class ExampleModel
@@ -30,12 +31,36 @@ class ExampleModel extends Model
3031
*/
3132
public $schedule;
3233

34+
public function init()
35+
{
36+
parent::init();
37+
$this->emails = [
38+
'test@test.com',
39+
'test2@test.com',
40+
'test3@test.com',
41+
];
42+
43+
$this->schedule = [
44+
[
45+
'day' => 0,
46+
'user_id' => 1,
47+
'priority' => 1
48+
],
49+
[
50+
'day' => 0,
51+
'user_id' => 2,
52+
'priority' => 2
53+
],
54+
];
55+
}
56+
3357

3458
public function rules()
3559
{
3660
return [
3761
['emails', 'validateEmails'],
38-
['phones', 'validatePhones']
62+
['phones', 'validatePhones'],
63+
['schedule', 'validateSchedule']
3964
];
4065
}
4166

@@ -50,7 +75,7 @@ public function attributes()
5075
public function scenarios()
5176
{
5277
return [
53-
self::SCENARIO_DEFAULT => ['emails', 'phones']
78+
self::SCENARIO_DEFAULT => ['emails', 'phones', 'schedule']
5479
];
5580
}
5681

@@ -97,18 +122,26 @@ public function validateEmails($attribute)
97122
$items = [];
98123
}
99124

100-
$multiple = true;
101-
if(!is_array($items)) {
102-
$multiple = false;
103-
$items = (array) $items;
104-
}
105-
106125
foreach ($items as $index => $item) {
107126
$validator = new EmailValidator();
108127
$error = null;
109128
$validator->validate($item, $error);
110129
if (!empty($error)) {
111-
$key = $attribute . ($multiple ? '[' . $index . ']' : '');
130+
$key = $attribute . '[' . $index . ']';
131+
$this->addError($key, $error);
132+
}
133+
}
134+
}
135+
136+
public function validateSchedule($attribute)
137+
{
138+
$requiredValidator = new RequiredValidator();
139+
140+
foreach($this->$attribute as $index => $row) {
141+
$error = null;
142+
$requiredValidator->validate($row['priority'], $error);
143+
if (!empty($error)) {
144+
$key = $attribute . '[' . $index . '][priority]';
112145
$this->addError($key, $error);
113146
}
114147
}

0 commit comments

Comments
 (0)