Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update branch 2.2. #19955

Merged
merged 12 commits into from
Sep 20, 2023
2 changes: 1 addition & 1 deletion docs/guide-ru/runtime-bootstrapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

В конструкторе приложения происходит следующий процесс предзагрузки:

1. Вызывается метод [[yii\base\Application::preInit()|preInit()]], которые конфигурирует свойства приложения, имеющие
1. Вызывается метод [[yii\base\Application::preInit()|preInit()]], который конфигурирует свойства приложения, имеющие
наивысший приоритет, такие как [[yii\base\Application::basePath|basePath]];
2. Регистрируется [[yii\base\Application::errorHandler|обработчик ошибок]];
3. Происходит инициализация свойств приложения согласно заданной конфигурации;
Expand Down
2 changes: 1 addition & 1 deletion framework/BaseYii.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class BaseYii
*/
public static function getVersion()
{
return '2.0.49-dev';
return '2.0.50-dev';
terabytesoftw marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
25 changes: 18 additions & 7 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,32 @@ Yii Framework 2 Change Log


2.0.49 under development
2.0.50 under development
terabytesoftw marked this conversation as resolved.
Show resolved Hide resolved
------------------------

- 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 #19925: Improved PHP version check when handling MIME types (schmunk42)
- Bug #19940: File Log writer without newline (terabytesoftw)
- Bug #19951: Removed unneeded MIME file tests (schmunk42)


2.0.49 August 29, 2023
----------------------

- 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)
- Bug #18859: Fix `yii\web\Controller::bindInjectedParams()` to not throw error when argument of `ReflectionUnionType` type is passed (bizley)
- Enh #19841: Allow jQuery 3.7 to be installed (wouter90)
- Enh #19853: Added support for default value for `\yii\helpers\Console::select()` (rhertogh)
- Bug #19857: Fix AttributeTypecastBehavior::resetOldAttributes() causes "class has no attribute named" InvalidArgumentException (uaoleg)
- Bug #19868: Added whitespace sanitation for tests, due to updates in ICU 72 (schmunk42)
- Enh #19884: Added support Enums in Query Builder (sk1t0n)
- Bug #19908: Fix associative array cell content rendering in Table widget (rhertogh)
- 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 #19906: Fixed multiline strings in the `\yii\console\widgets\Table` widget (rhertogh)
- Bug #19908: Fix associative array cell content rendering in Table widget (rhertogh)
- 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 #19914: Fixed `ArrayHelper::keyExists()` and `::remove()` functions when the key is a float and the value is `null` (rhertogh)
- Bug #19924: Fix `yii\i18n\Formatter` to not throw error `Unknown named parameter` under PHP 8 (arollmann)
- Enh #19841: Allow jQuery 3.7 to be installed (wouter90)
- Enh #19853: Added support for default value for `\yii\helpers\Console::select()` (rhertogh)
- Enh #19884: Added support Enums in Query Builder (sk1t0n)
- Enh #19920: Broadened the accepted type of `Cookie::$expire` from `int` to `int|string|\DateTimeInterface|null` (rhertogh)


Expand Down
5 changes: 5 additions & 0 deletions framework/UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
-----------------------
Expand Down
56 changes: 31 additions & 25 deletions framework/db/BaseActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -1609,40 +1609,46 @@ public static function isPrimaryKey($keys)

/**
* 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);
$model = $this;
$modelAttribute = $attribute;
for (;;) {
$labels = $model->attributeLabels();
if (isset($labels[$modelAttribute])) {
return $labels[$modelAttribute];
}

$relatedModel = $this;
foreach ($attributeParts as $relationName) {
if ($relatedModel->isRelationPopulated($relationName) && $relatedModel->$relationName instanceof self) {
$relatedModel = $relatedModel->$relationName;
} else {
try {
$relation = $relatedModel->getRelation($relationName);
} catch (InvalidArgumentException $e) {
return $this->generateAttributeLabel($attribute);
}
/* @var $modelClass ActiveRecordInterface */
$modelClass = $relation->modelClass;
$relatedModel = $modelClass::instance();
}
$parts = explode('.', $modelAttribute, 2);
if (count($parts) < 2) {
break;
}

$labels = $relatedModel->attributeLabels();
if (isset($labels[$neededAttribute])) {
return $labels[$neededAttribute];
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();
}
}

Expand Down
2 changes: 1 addition & 1 deletion framework/db/Migration.php
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ public function delete($table, $condition = '', $params = [])
* // ...
* 'column_name double precision null default null',
* ```

*
*
* @param string $table the name of the table to be created. The name will be properly quoted by the method.
* @param array $columns the columns (name => definition) in the new table.
Expand Down
2 changes: 2 additions & 0 deletions framework/helpers/mimeExtensions.php
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@
'application/vnd.fuzzysheet' => 'fzs',
'application/vnd.genomatix.tuxedo' => 'txd',
'application/vnd.geogebra.file' => 'ggb',
'application/vnd.geogebra.slides' => 'ggs',
'application/vnd.geogebra.tool' => 'ggt',
'application/vnd.geometry-explorer' => [
'gex',
Expand Down Expand Up @@ -655,6 +656,7 @@
],
'application/vnd.zzazz.deck+xml' => 'zaz',
'application/voicexml+xml' => 'vxml',
'application/wasm' => 'wasm',
'application/widget' => 'wgt',
'application/winhlp' => 'hlp',
'application/wsdl+xml' => 'wsdl',
Expand Down
5 changes: 4 additions & 1 deletion framework/helpers/mimeTypes.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@
'geo' => 'application/vnd.dynageo',
'gex' => 'application/vnd.geometry-explorer',
'ggb' => 'application/vnd.geogebra.file',
'ggs' => 'application/vnd.geogebra.slides',
'ggt' => 'application/vnd.geogebra.tool',
'ghf' => 'application/vnd.groove-help',
'gif' => 'image/gif',
Expand Down Expand Up @@ -887,6 +888,7 @@
'vxml' => 'application/voicexml+xml',
'w3d' => 'application/x-director',
'wad' => 'application/x-doom',
'wasm' => 'application/wasm',
'wav' => 'audio/x-wav',
'wax' => 'audio/x-ms-wax',
'wbmp' => 'image/vnd.wap.wbmp',
Expand Down Expand Up @@ -1001,7 +1003,8 @@
'zmm' => 'application/vnd.handheld-entertainment+xml',
];

if (PHP_VERSION_ID >= 80100) {
# fix for bundled libmagic bug, see also https://github.com/yiisoft/yii2/issues/19925
if ((PHP_VERSION_ID >= 80100 && PHP_VERSION_ID < 80122) || (PHP_VERSION_ID >= 80200 && PHP_VERSION_ID < 80209)) {
$mimeTypes = array_replace($mimeTypes, array('xz' => 'application/octet-stream'));
}

Expand Down
2 changes: 1 addition & 1 deletion framework/i18n/Formatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ public function format($value, $format)
}
$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");
Expand Down
4 changes: 2 additions & 2 deletions framework/log/FileTarget.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,12 @@ public function export()
if ($this->enableRotation && @filesize($this->logFile) > $this->maxFileSize * 1024) {
$this->rotateFiles();
}
$writeResult = @fwrite($fp, $trimmedText);
$writeResult = @fwrite($fp, $text);
if ($writeResult === false) {
$error = error_get_last();
throw new LogRuntimeException("Unable to export log through file ({$this->logFile})!: {$error['message']}");
}
$textSize = strlen($trimmedText);
$textSize = strlen($text);
if ($writeResult < $textSize) {
throw new LogRuntimeException("Unable to export whole log through file ({$this->logFile})! Wrote $writeResult out of $textSize bytes.");
}
Expand Down
84 changes: 84 additions & 0 deletions tests/framework/db/ActiveRecordTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2205,4 +2205,88 @@ public function testVirtualRelation()

$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::class, []);
}
}

class LabelTestModel2 extends \yii\db\ActiveRecord
{
public function attributes()
{
return [];
}

public function getModel3()
{
return $this->hasOne(LabelTestModel3::class, []);
}

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',
];
}
}
Loading