-
Notifications
You must be signed in to change notification settings - Fork 128
/
Copy pathMultipleInputColumn.php
183 lines (152 loc) · 5.19 KB
/
MultipleInputColumn.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
<?php
/**
* @link https://github.com/unclead/yii2-multiple-input
* @copyright Copyright (c) 2014 unclead
* @license https://github.com/unclead/yii2-multiple-input/blob/master/LICENSE.md
*/
namespace unclead\multipleinput;
use yii\base\InvalidConfigException;
use yii\base\Model;
use yii\base\DynamicModel;
use yii\db\ActiveRecordInterface;
use yii\helpers\Html;
use unclead\multipleinput\components\BaseColumn;
/**
* Class MultipleInputColumn
* @package unclead\multipleinput
*
* @property MultipleInput $context
*/
class MultipleInputColumn extends BaseColumn
{
/**
* @throws InvalidConfigException
*/
public function init()
{
parent::init();
if ($this->enableError && !$this->context->model instanceof Model) {
throw new InvalidConfigException('Property "enableError" available only when model is defined.');
}
}
/**
* Returns element's name.
*
* @param int|null|string $index current row index
* @param bool $withPrefix whether to add prefix.
*
* @return string
*/
public function getElementName($index, $withPrefix = true)
{
if ($index === null) {
$index = '{' . $this->renderer->getIndexPlaceholder() . '}';
}
if ($this->isRendererHasOneColumn()) {
$prefix = $this->getInputNamePrefix();
if ($prefix === '') {
$elementName = $this->name . '[' . $index . ']';
} else {
$elementName = '[' . $this->name . '][' . $index . ']';
}
} else {
$elementName = '[' . $index . '][' . $this->name . ']';
}
if (!$withPrefix) {
return $elementName;
}
$prefix = $this->getInputNamePrefix();
if ($this->context->isEmbedded && strpos($prefix, $this->context->name) === false) {
$prefix = $this->context->name;
}
return $prefix . $elementName . (empty($this->nameSuffix) ? '' : ('_' . $this->nameSuffix));
}
/**
* @return bool
*/
private function isRendererHasOneColumn()
{
$columns = \array_filter($this->renderer->columns, function(self $column) {
return $column->type !== self::TYPE_DRAGCOLUMN;
});
return count($columns) === 1;
}
/**
* Return prefix for name of input.
*
* @return string
*/
protected function getInputNamePrefix()
{
$model = $this->context->model;
if ($model instanceof Model) {
if (empty($this->renderer->columns) || ($this->isRendererHasOneColumn() && $this->hasModelAttribute($this->name))) {
return $model->formName();
}
return Html::getInputName($this->context->model, $this->context->attribute);
}
return $this->context->name;
}
protected function hasModelAttribute($name)
{
$model = $this->context->model;
if ($model->hasProperty($name)) {
return true;
}
if ($model instanceof ActiveRecordInterface && $model->hasAttribute($name)) {
return true;
}
if ($model instanceof DynamicModel && isset($model->{$name})) {
return true;
}
return false;
}
/**
* @param int|string|null $index
* @return null|string
*/
public function getFirstError($index)
{
if ($index === null) {
return null;
}
if ($this->isRendererHasOneColumn()) {
$attribute = $this->name . '[' . $index . ']';
} else {
$attribute = $this->context->attribute . $this->getElementName($index, false);
}
$model = $this->context->model;
if ($model instanceof Model) {
return $model->getFirstError($attribute);
}
return null;
}
/**
* @inheritdoc
*/
protected function renderWidget($type, $name, $value, $options)
{
// Extend options in case of rendering embedded MultipleInput
// We have to pass to the widget an original model and an attribute to be able get a first error from model
// for embedded widget.
if ($type === MultipleInput::className()) {
$model = $this->context->model;
// in case of embedding level 2 and more
if (preg_match('/^([\w\.]+)(\[.*)$/', $this->context->attribute, $matches)) {
$search = sprintf('%s[%s]%s', $model->formName(), $matches[1], $matches[2]);
} else {
$search = sprintf('%s[%s]', $model->formName(), $this->context->attribute);
}
$replace = $this->context->attribute;
$attribute = str_replace($search, $replace, $name);
$options['model'] = $model;
$options['attribute'] = $attribute;
// Remember current name and mark the widget as embedded to prevent
// generation of wrong prefix in case the column is associated with AR relation
// @see https://github.com/unclead/yii2-multiple-input/issues/92
$options['name'] = $name;
$options['isEmbedded'] = true;
}
return parent::renderWidget($type, $name, $value, $options);
}
}