mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-10-31 18:47:33 +08:00 
			
		
		
		
	Merge branch 'master' into 13920-validation-marks-valid-field-as-invalid
This commit is contained in:
		| @ -5,6 +5,7 @@ Yii Framework 2 Change Log | ||||
| ------------------------ | ||||
|  | ||||
| - Bug #13920: Fixed erroneous validation for specific cases (tim-fischer-maschinensucher) | ||||
| - Bug #19911: Resolved inconsistency in `ActiveRecord::getAttributeLabel()` with regard of overriding in primary model labels for attributes of related model in favor of allowing such overriding for all levels of relation nesting (PowerGamer1) | ||||
| - Bug #19872: Fixed the definition of dirty attributes in AR properties for a non-associative array in case of changing the order of elements (eegusakov) | ||||
| - 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) | ||||
| @ -17,6 +18,7 @@ Yii Framework 2 Change Log | ||||
| - Enh #19884: Added support Enums in Query Builder (sk1t0n) | ||||
| - Bug #19908: Fix associative array cell content rendering in Table widget (rhertogh) | ||||
| - Bug #19906: Fixed multiline strings in the `\yii\console\widgets\Table` widget (rhertogh) | ||||
| - Bug #19924: Fix `yii\i18n\Formatter` to not throw error `Unknown named parameter` under PHP 8 (arollmann) | ||||
| - Bug #19914: Fixed `ArrayHelper::keyExists()` and  `::remove()` functions when the key is a float and the value is `null` (rhertogh) | ||||
| - Enh #19920: Broadened the accepted type of `Cookie::$expire` from `int` to `int|string|\DateTimeInterface|null` (rhertogh) | ||||
|  | ||||
|  | ||||
| @ -100,6 +100,11 @@ Upgrade from Yii 2.0.45 | ||||
|   2.0.45 behavior, [introduce your own method](https://github.com/yiisoft/yii2/pull/19495/files). | ||||
| * `yii\log\FileTarget::$rotateByCopy` is now deprecated and setting it to `false` has no effect since rotating of  | ||||
|   the files is done only by copy. | ||||
| * `yii\validators\UniqueValidator` and `yii\validators\ExistValidator`, when used on multiple attributes, now only | ||||
|   generate an error on a single attribute. Previously, they would report a separate error on each attribute. | ||||
|   Old behavior can be achieved by setting `'skipOnError' => false`, but this might have undesired side effects with | ||||
|   additional validators on one of the target attributes. | ||||
|   See [issue #19407](https://github.com/yiisoft/yii2/issues/19407) | ||||
|  | ||||
| Upgrade from Yii 2.0.44 | ||||
| ----------------------- | ||||
|  | ||||
| @ -1610,40 +1610,46 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface | ||||
|  | ||||
|     /** | ||||
|      * Returns the text label for the specified attribute. | ||||
|      * If the attribute looks like `relatedModel.attribute`, then the attribute will be received from the related model. | ||||
|      * The attribute may be specified in a dot format to retrieve the label from related model or allow this model to override the label defined in related model. | ||||
|      * For example, if the attribute is specified as 'relatedModel1.relatedModel2.attr' the function will return the first label definition it can find | ||||
|      * in the following order: | ||||
|      * - the label for 'relatedModel1.relatedModel2.attr' defined in [[attributeLabels()]] of this model; | ||||
|      * - the label for 'relatedModel2.attr' defined in related model represented by relation 'relatedModel1' of this model; | ||||
|      * - the label for 'attr' defined in related model represented by relation 'relatedModel2' of relation 'relatedModel1'. | ||||
|      * If no label definition was found then the value of $this->generateAttributeLabel('relatedModel1.relatedModel2.attr') will be returned. | ||||
|      * @param string $attribute the attribute name | ||||
|      * @return string the attribute label | ||||
|      * @see generateAttributeLabel() | ||||
|      * @see attributeLabels() | ||||
|      * @see generateAttributeLabel() | ||||
|      */ | ||||
|     public function getAttributeLabel($attribute) | ||||
|     { | ||||
|         $labels = $this->attributeLabels(); | ||||
|         if (isset($labels[$attribute])) { | ||||
|             return $labels[$attribute]; | ||||
|         } elseif (strpos($attribute, '.')) { | ||||
|             $attributeParts = explode('.', $attribute); | ||||
|             $neededAttribute = array_pop($attributeParts); | ||||
|  | ||||
|             $relatedModel = $this; | ||||
|             foreach ($attributeParts as $relationName) { | ||||
|                 if ($relatedModel->isRelationPopulated($relationName) && $relatedModel->$relationName instanceof self) { | ||||
|                     $relatedModel = $relatedModel->$relationName; | ||||
|                 } else { | ||||
|                     try { | ||||
|                         $relation = $relatedModel->getRelation($relationName); | ||||
|                     } catch (InvalidParamException $e) { | ||||
|                         return $this->generateAttributeLabel($attribute); | ||||
|                     } | ||||
|                     /* @var $modelClass ActiveRecordInterface */ | ||||
|                     $modelClass = $relation->modelClass; | ||||
|                     $relatedModel = $modelClass::instance(); | ||||
|                 } | ||||
|         $model = $this; | ||||
|         $modelAttribute = $attribute; | ||||
|         for (;;) { | ||||
|             $labels = $model->attributeLabels(); | ||||
|             if (isset($labels[$modelAttribute])) { | ||||
|                 return $labels[$modelAttribute]; | ||||
|             } | ||||
|  | ||||
|             $labels = $relatedModel->attributeLabels(); | ||||
|             if (isset($labels[$neededAttribute])) { | ||||
|                 return $labels[$neededAttribute]; | ||||
|             $parts = explode('.', $modelAttribute, 2); | ||||
|             if (count($parts) < 2) { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             list ($relationName, $modelAttribute) = $parts; | ||||
|  | ||||
|             if ($model->isRelationPopulated($relationName) && $model->$relationName instanceof self) { | ||||
|                 $model = $model->$relationName; | ||||
|             } else { | ||||
|                 try { | ||||
|                     $relation = $model->getRelation($relationName); | ||||
|                 } catch (InvalidArgumentException $e) { | ||||
|                     break; | ||||
|                 } | ||||
|                 /* @var $modelClass ActiveRecordInterface */ | ||||
|                 $modelClass = $relation->modelClass; | ||||
|                 $model = $modelClass::instance(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
| @ -460,7 +460,7 @@ class Formatter extends Component | ||||
|         } | ||||
|         $method = 'as' . $format; | ||||
|         if ($this->hasMethod($method)) { | ||||
|             return call_user_func_array([$this, $method], $params); | ||||
|             return call_user_func_array([$this, $method], array_values($params)); | ||||
|         } | ||||
|  | ||||
|         throw new InvalidArgumentException("Unknown format type: $format"); | ||||
|  | ||||
| @ -2192,4 +2192,87 @@ abstract class ActiveRecordTest extends DatabaseTestCase | ||||
|         $this->assertNotNull($order->virtualCustomer); | ||||
|     } | ||||
|  | ||||
|     public function labelTestModelProvider() | ||||
|     { | ||||
|         $data = []; | ||||
|  | ||||
|         // Model 2 and 3 are represented by objects. | ||||
|         $model1 = new LabelTestModel1(); | ||||
|         $model2 = new LabelTestModel2(); | ||||
|         $model3 = new LabelTestModel3(); | ||||
|         $model2->populateRelation('model3', $model3); | ||||
|         $model1->populateRelation('model2', $model2); | ||||
|         $data[] = [$model1]; | ||||
|  | ||||
|         // Model 2 and 3 are represented by arrays instead of objects. | ||||
|         $model1 = new LabelTestModel1(); | ||||
|         $model2 = ['model3' => []]; | ||||
|         $model1->populateRelation('model2', $model2); | ||||
|         $data[] = [$model1]; | ||||
|  | ||||
|         return $data; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @dataProvider labelTestModelProvider | ||||
|      * @param \yii\db\ActiveRecord $model | ||||
|      */ | ||||
|     public function testGetAttributeLabel($model) | ||||
|     { | ||||
|         $this->assertEquals('model3.attr1 from model2', $model->getAttributeLabel('model2.model3.attr1')); | ||||
|         $this->assertEquals('attr2 from model3', $model->getAttributeLabel('model2.model3.attr2')); | ||||
|         $this->assertEquals('model3.attr3 from model2', $model->getAttributeLabel('model2.model3.attr3')); | ||||
|         $attr = 'model2.doesNotExist.attr1'; | ||||
|         $this->assertEquals($model->generateAttributeLabel($attr), $model->getAttributeLabel($attr)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| class LabelTestModel1 extends \yii\db\ActiveRecord | ||||
| { | ||||
|     public function attributes() | ||||
|     { | ||||
|         return []; | ||||
|     } | ||||
|  | ||||
|     public function getModel2() | ||||
|     { | ||||
|         return $this->hasOne(LabelTestModel2::className(), []); | ||||
|     } | ||||
| } | ||||
|  | ||||
| class LabelTestModel2 extends \yii\db\ActiveRecord | ||||
| { | ||||
|     public function attributes() | ||||
|     { | ||||
|         return []; | ||||
|     } | ||||
|  | ||||
|     public function getModel3() | ||||
|     { | ||||
|         return $this->hasOne(LabelTestModel3::className(), []); | ||||
|     } | ||||
|  | ||||
|     public function attributeLabels() | ||||
|     { | ||||
|         return [ | ||||
|             'model3.attr1' => 'model3.attr1 from model2', // Override label defined in model3. | ||||
|             'model3.attr3' => 'model3.attr3 from model2', // Define label not defined in model3. | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| class LabelTestModel3 extends \yii\db\ActiveRecord | ||||
| { | ||||
|     public function attributes() | ||||
|     { | ||||
|         return ['attr1', 'attr2', 'attr3']; | ||||
|     } | ||||
|  | ||||
|     public function attributeLabels() | ||||
|     { | ||||
|         return [ | ||||
|             'attr1' => 'attr1 from model3', | ||||
|             'attr2' => 'attr2 from model3', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Alexander Makarov
					Alexander Makarov