-
-
Notifications
You must be signed in to change notification settings - Fork 34
Description
Description:
In kartik-v/yii2-widget-activeform version 1.6.4, the initHorizontal() method in ActiveField.php incorrectly concatenates default grid classes (col-md-2 for and col-md-10 for wrappers) with user-defined classes specified in horizontalCssClasses['label'] and horizontalCssClasses['wrapper'] for horizontal forms (ActiveForm::TYPE_HORIZONTAL). This results in duplicate or unwanted classes, such as col-md-8 has-star col-md-2 col-md-8 for labels and col-md-10 col-md-16 for input wrappers, even when custom classes are explicitly defined.
The issue occurs because the method does not replace the default classes calculated from labelSpan (default 2, yielding col-md-2 and col-md-10) when horizontalCssClasses is provided. Instead, it appends the custom classes, leading to incorrect grid layouts. Additionally, the logic to nullify labelSpan when horizontalCssClasses['wrapper'] contains a col-* class is unreliable, as it fails under certain conditions (e.g., when wrapper is processed as an array or due to configuration overrides).
Environment:
Package: kartik-v/yii2-widget-activeform:1.6.4 (probably it could be there since >1.6.0)
Yii2 Version: yiisoft/yii2:2.0.49
Bootstrap Dependency: yiisoft/yii2-bootstrap:2.x (Bootstrap 3)
PHP Version: 7.4 or higher
Steps to Reproduce:
- Create a horizontal form with custom grid classes:
use kartik\form\ActiveForm;
$form = ActiveForm::begin([
'type' => ActiveForm::TYPE_HORIZONTAL,
'fieldConfig' => [
'horizontalCssClasses' => [
'label' => 'col-md-8',
'wrapper' => 'col-md-16',
],
],
]);
echo $form->field($model, 'test')->textInput();
ActiveForm::end();
Render the form and inspect the generated HTML.
Expected Behavior:
The should have classes: control-label col-md-8 has-star (assuming showRequiredIndicator = true).
The wrapper
Actual Behavior:
The has classes: col-md-8 has-star col-md-2 col-md-8 (duplicate col-md-8 and unwanted col-md-2).
The wrapper
Cause:
In ActiveField::initHorizontal() (lines 1025-1088 in src/ActiveField.php):
The default _labelCss is set to col-md-2 and _inputCss to col-md-10 based on labelSpan = 2 and fullSpan = 12.
Custom classes from horizontalCssClasses['label'] and horizontalCssClasses['wrapper'] are appended to _labelCss and _inputCss (lines 1077-1080) instead of replacing them.
The condition to nullify labelSpan (if (isset($hor['wrapper']) && Lib::strpos($hor['wrapper'], 'col-') !== false)) does not consistently prevent the default classes from being applied, possibly due to type handling or configuration overrides (e.g., formConfig['labelSpan']).
Proposed Solution:
Modify initHorizontal() to:
Replace _labelCss and _inputCss with horizontalCssClasses['label'] and horizontalCssClasses['wrapper'] when defined, instead of appending.
Ensure labelSpan is nullified when horizontalCssClasses['wrapper'] contains col-*, preventing default classes.
Clear _labelCss and _inputCss when labelSpan is invalid or nullified.
Below is the corrected initHorizontal() method:
protected function initHorizontal()
{
$hor = $this->horizontalCssClasses;
$span = $this->getConfigParam('labelSpan', '');
$size = $this->getConfigParam('deviceSize', '');
$bsVer = $this->form->getBsVer();
if ($bsVer > 3) {
Html::addCssClass($this->options, 'row');
}
// check horizontalCssClasses['wrapper'] if there is a col- class
if (isset($hor['wrapper']) && (is_string($hor['wrapper']) && strpos($hor['wrapper'], 'col-') !== false)) {
$span = '';
}
if (empty($span) && !isset($hor['wrapper'])) {
$span = $this->_settings['labelSpan'];
}
if (empty($size)) {
$size = ArrayHelper::getValue($this->_settings, 'deviceSize');
}
$this->deviceSize = $size;
if (empty($span)) {
$span = ActiveForm::DEFAULT_LABEL_SPAN;
}
if ($span != self::NOT_SET && intval($span) > 0) {
$span = intval($span);
if ($span <= 0 || $span >= $this->form->fullSpan) {
$span = $this->form->fullSpan;
}
$sizes = [ActiveForm::SIZE_TINY, ActiveForm::SIZE_SMALL, ActiveForm::SIZE_MEDIUM, ActiveForm::SIZE_LARGE];
if ($size == self::NOT_SET || !in_array($size, $sizes)) {
$size = ActiveForm::SIZE_MEDIUM;
}
$this->labelSpan = $span;
$prefix = $this->getColCss($size);
$this->_labelCss = isset($hor['label']) ? '' : $prefix.$span;
$this->_inputCss = isset($hor['wrapper']) ? '' : $prefix.($this->form->fullSpan - $span);
} else {
$this->_labelCss = '';
$this->_inputCss = '';
}
if (isset($hor['wrapper'])) {
$this->_inputCss = implode(' ', (array)$hor['wrapper']);
}
if (isset($hor['label'])) {
$this->_labelCss = implode(' ', (array)$hor['label']);
}
if (isset($hor['error'])) {
Html::addCssClass($this->errorOptions, $hor['error']);
}
}
Additional Notes:
The issue was observed in a project using Bootstrap 3 (yiisoft/yii2-bootstrap:2.x), but it may also affect Bootstrap 4 setups.
The bug is likely introduced or exacerbated by enhancement #108 in version 1.6.4 (bootstrap grid column CSS size map configuration).
A patch script to apply the fix is available if needed (can be shared upon request).
Please consider applying this fix in the next release to ensure proper grid class handling in horizontal forms.
Attachments:
Example form code (above).
Proposed initHorizontal() method (above).