diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index ce580c49bef..dc620a07486 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.0.49 under development ------------------------ +- Bug #19899: Fixed `GridView` in some cases calling `Model::generateAttributeLabel()` to generate label values that are never used (PowerGamer1) - Bug #9899: Fix caching a MSSQL query with BLOB data type (terabytesoftw) - Bug #16208: Fix `yii\log\FileTarget` to not export empty messages (terabytesoftw) - Bug #19857: Fix AttributeTypecastBehavior::resetOldAttributes() causes "class has no attribute named" InvalidArgumentException (uaoleg) diff --git a/framework/data/ActiveDataProvider.php b/framework/data/ActiveDataProvider.php index a8b6e158ecf..3a129aa7293 100644 --- a/framework/data/ActiveDataProvider.php +++ b/framework/data/ActiveDataProvider.php @@ -183,15 +183,11 @@ public function setSort($value) $sort->attributes[$attribute] = [ 'asc' => [$attribute => SORT_ASC], 'desc' => [$attribute => SORT_DESC], - 'label' => $model->getAttributeLabel($attribute), ]; } - } else { - foreach ($sort->attributes as $attribute => $config) { - if (!isset($config['label'])) { - $sort->attributes[$attribute]['label'] = $model->getAttributeLabel($attribute); - } - } + } + if ($sort->modelClass === null) { + $sort->modelClass = $modelClass; } } } diff --git a/framework/data/Sort.php b/framework/data/Sort.php index 1ed63f4ac87..0c0abc8b606 100644 --- a/framework/data/Sort.php +++ b/framework/data/Sort.php @@ -191,6 +191,12 @@ class Sort extends BaseObject * @since 2.0.33 */ public $sortFlags = SORT_REGULAR; + /** + * @var string|null the name of the [[\yii\base\Model]]-based class used by the [[link()]] method to retrieve + * attributes' labels. See [[link]] method for details. + * @since 2.0.49 + */ + public $modelClass; /** @@ -363,7 +369,8 @@ public function getAttributeOrder($attribute) * @param array $options additional HTML attributes for the hyperlink tag. * There is one special attribute `label` which will be used as the label of the hyperlink. * If this is not set, the label defined in [[attributes]] will be used. - * If no label is defined, [[\yii\helpers\Inflector::camel2words()]] will be called to get a label. + * If no label is defined, it will be retrieved from the instance of [[modelClass]] (if [[modelClass]] is not null) + * or generated from attribute name using [[\yii\helpers\Inflector::camel2words()]]. * Note that it will not be HTML-encoded. * @return string the generated hyperlink * @throws InvalidConfigException if the attribute is unknown @@ -388,6 +395,11 @@ public function link($attribute, $options = []) } else { if (isset($this->attributes[$attribute]['label'])) { $label = $this->attributes[$attribute]['label']; + } elseif ($this->modelClass !== null) { + $modelClass = $this->modelClass; + /** @var \yii\base\Model $model */ + $model = $modelClass::instance(); + $label = $model->getAttributeLabel($attribute); } else { $label = Inflector::camel2words($attribute); } diff --git a/tests/data/ar/NoAutoLabels.php b/tests/data/ar/NoAutoLabels.php new file mode 100644 index 00000000000..e33a3847d84 --- /dev/null +++ b/tests/data/ar/NoAutoLabels.php @@ -0,0 +1,27 @@ + 'Label for attr1', + ]; + } + + public function generateAttributeLabel($name) + { + throw new \yii\base\InvalidArgumentException('Label not defined!'); + } +} diff --git a/tests/framework/grid/GridViewTest.php b/tests/framework/grid/GridViewTest.php index 392aefbd0ba..b698011493b 100644 --- a/tests/framework/grid/GridViewTest.php +++ b/tests/framework/grid/GridViewTest.php @@ -7,10 +7,12 @@ namespace yiiunit\framework\grid; +use Yii; use yii\data\ArrayDataProvider; use yii\grid\DataColumn; use yii\grid\GridView; use yii\web\View; +use yiiunit\data\ar\NoAutoLabels; /** * @author Evgeniy Tkachenko @@ -150,4 +152,53 @@ public function testFooter() { $this->assertTrue(preg_match("/<\/tbody>/", $html) === 1); } + + public function testHeaderLabels() + { + // Ensure GridView does not call Model::generateAttributeLabel() to generate labels unless the labels are explicitly used. + + $this->mockApplication([ + 'components' => [ + 'db' => [ + 'class' => \yii\db\Connection::className(), + 'dsn' => 'sqlite::memory:', + ], + ], + ]); + + NoAutoLabels::$db = Yii::$app->getDb(); + Yii::$app->getDb()->createCommand()->createTable(NoAutoLabels::tableName(), ['attr1' => 'int', 'attr2' => 'int'])->execute(); + + $urlManager = new \yii\web\UrlManager([ + 'baseUrl' => '/', + 'scriptUrl' => '/index.php', + ]); + + $grid = new GridView([ + 'dataProvider' => new \yii\data\ActiveDataProvider([ + 'query' => NoAutoLabels::find(), + ]), + 'columns' => [ + 'attr1', + 'attr2:text:Label for attr2', + ], + ]); + + // NoAutoLabels::generateAttributeLabel() should not be called. + $grid->dataProvider->setSort([ + 'route' => '/', + 'urlManager' => $urlManager, + ]); + $grid->renderTableHeader(); + + // NoAutoLabels::generateAttributeLabel() should not be called. + $grid->dataProvider->setSort([ + 'route' => '/', + 'urlManager' => $urlManager, + 'attributes' => ['attr1', 'attr2'], + ]); + $grid->renderTableHeader(); + + // If NoAutoLabels::generateAttributeLabel() has not been called no exception will be thrown meaning this test passed successfully. + } }