From 5fb3f809c59f742537df77e0da1ad36a1175834a Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 15 Apr 2025 00:41:12 +0300 Subject: [PATCH 01/13] Add a link to release cycle page at the website instead of direct description --- README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/README.md b/README.md index 4bc05115c8..37bea62dda 100644 --- a/README.md +++ b/README.md @@ -37,16 +37,7 @@ to get an idea of what has changed in 2.0. Versions & PHP compatibility ---------------------------- -| Yii2 Version | PHP version | Development status | EOL ¹ | -|--------------|----------------|-----------------------------------|----------------------------------------------------------------| -| <= 2.0.49.* | >= 5.4, <= 8.3 | security fixes only | 23 Nov 2026 ³ | -| >= 2.0.50 | >= 7.3, <= 8.4 | bug fixes and security fixes only | bugfixes till 23 Nov 2026 ³, security fixes till 21 Nov 2027 ⁴ | -| >= 2.2.0 ² | >= 8.1 | active development | | - -¹ All mentioned dates may be subject to change and no rights can be derived from them. -² Note: Yii 2.1 was [skipped](https://github.com/yiisoft/yii2/discussions/19831#discussioncomment-5858046), [Yii 2.2](https://github.com/yiisoft/yii2/tree/2.2) has not yet been released. -³ [PHP 8.3 EOL date](https://www.php.net/supported-versions.php). -⁴ [Expected PHP 8.4 EOL date](https://wiki.php.net/todo/php84). +See ["Release Cycle" at the website](https://www.yiiframework.com/release-cycle). Community --------- From 7037fd46abd480330425cab30ce58e180e9d8ead Mon Sep 17 00:00:00 2001 From: Wilmer Arambula <42547589+terabytesoftw@users.noreply.github.com> Date: Sat, 19 Apr 2025 16:15:28 -0400 Subject: [PATCH 02/13] Fix #20355: Fix SQL syntax for resetting sequence in `QueryBuilder` for `MSSQL` --- .github/workflows/ci-mssql.yml | 5 ----- framework/CHANGELOG.md | 1 + framework/db/mssql/QueryBuilder.php | 4 +++- tests/framework/db/mssql/QueryBuilderTest.php | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-mssql.yml b/.github/workflows/ci-mssql.yml index d9af9335aa..40e19b8c86 100644 --- a/.github/workflows/ci-mssql.yml +++ b/.github/workflows/ci-mssql.yml @@ -34,11 +34,6 @@ jobs: mssql-tool: /opt/mssql-tools18/bin/sqlcmd -C include: - - php: 7.4 - mssql: - version: server:2017-latest - mssql-tool: /opt/mssql-tools/bin/sqlcmd - os: ubuntu-22.04 - php: 8.0 mssql: version: server:2019-latest diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 2186e40a15..37e07e23c6 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -8,6 +8,7 @@ Yii Framework 2 Change Log - Bug #20329: pgsql: Column Schema doesn't recognize PG type cast (arkhamvm) - Bug #8298: Loading fixtures does not update table sequence for Postgresql database (mtangoo) - Bug #20347: Fix compatibility with PHP 8.4: remove usage of `session.use_trans_sid` and `session.use_only_cookies` (tehmaestro) +- Bug #20355: Fix SQL syntax for resetting sequence in `QueryBuilder` for `MSSQL` (terabytesoftw) 2.0.52 February 13, 2025 diff --git a/framework/db/mssql/QueryBuilder.php b/framework/db/mssql/QueryBuilder.php index b1780617cc..1605e44524 100644 --- a/framework/db/mssql/QueryBuilder.php +++ b/framework/db/mssql/QueryBuilder.php @@ -247,9 +247,11 @@ class QueryBuilder extends \yii\db\QueryBuilder $table = $this->db->getTableSchema($tableName); if ($table !== null && $table->sequenceName !== null) { $tableName = $this->db->quoteTableName($tableName); + if ($value === null) { $key = $this->db->quoteColumnName(reset($table->primaryKey)); - $value = "(SELECT COALESCE(MAX({$key}),0) FROM {$tableName})+1"; + $sql = "SELECT COALESCE(MAX({$key}), 0) + 1 FROM {$tableName}"; + $value = $this->db->createCommand($sql)->queryScalar(); } else { $value = (int) $value; } diff --git a/tests/framework/db/mssql/QueryBuilderTest.php b/tests/framework/db/mssql/QueryBuilderTest.php index c1213d6bc9..dc6297a65e 100644 --- a/tests/framework/db/mssql/QueryBuilderTest.php +++ b/tests/framework/db/mssql/QueryBuilderTest.php @@ -364,7 +364,7 @@ class QueryBuilderTest extends \yiiunit\framework\db\QueryBuilderTest { $qb = $this->getQueryBuilder(); - $expected = "DBCC CHECKIDENT ('[item]', RESEED, (SELECT COALESCE(MAX([id]),0) FROM [item])+1)"; + $expected = "DBCC CHECKIDENT ('[item]', RESEED, 6)"; $sql = $qb->resetSequence('item'); $this->assertEquals($expected, $sql); From f046f242b7946b5206d7cdf50450a04ec26938de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= <63721828+max-s-lab@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:20:41 +0400 Subject: [PATCH 03/13] Generic types for DI classes (#20354) --- framework/di/Container.php | 11 +++++------ framework/di/Instance.php | 6 ++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/framework/di/Container.php b/framework/di/Container.php index 817f0b0a23..1d34887f45 100644 --- a/framework/di/Container.php +++ b/framework/di/Container.php @@ -158,12 +158,11 @@ class Container extends Component * @throws InvalidConfigException if the class cannot be recognized or correspond to an invalid definition * @throws NotInstantiableException If resolved to an abstract class or an interface (since 2.0.9) * - * - * @template T of class-string - * @psalm-param class-string|array{class: class-string} $class - * @phpstan-param class-string|array{class: class-string} $class - * @psalm-return T - * @phpstan-return T + * @template T of object + * @psalm-param string|class-string|Instance $class + * @phpstan-param string|class-string|Instance $class + * @psalm-return ($class is class-string ? T : object) + * @phpstan-return ($class is class-string ? T : object) */ public function get($class, $params = [], $config = []) { diff --git a/framework/di/Instance.php b/framework/di/Instance.php index edecbe9be8..020e817182 100644 --- a/framework/di/Instance.php +++ b/framework/di/Instance.php @@ -114,6 +114,12 @@ class Instance * @param ServiceLocator|Container|null $container the container. This will be passed to [[get()]]. * @return object the object referenced by the Instance, or `$reference` itself if it is an object. * @throws InvalidConfigException if the reference is invalid + * + * @template T of object + * @psalm-param class-string|null $type + * @phpstan-param class-string|null $type + * @psalm-return ($type is null ? object : T) + * @phpstan-return ($type is null ? object : T) */ public static function ensure($reference, $type = null, $container = null) { From 6dbdeb90918eb82e5d3fedba40425ae822c3f978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= <63721828+max-s-lab@users.noreply.github.com> Date: Sun, 27 Apr 2025 13:12:12 +0400 Subject: [PATCH 04/13] save (#20361) --- framework/db/ActiveQuery.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/framework/db/ActiveQuery.php b/framework/db/ActiveQuery.php index 67d48b98b9..ed1e350f66 100644 --- a/framework/db/ActiveQuery.php +++ b/framework/db/ActiveQuery.php @@ -71,6 +71,10 @@ use yii\base\InvalidConfigException; * @since 2.0 * * @template T of (ActiveRecord|array) + * @phpstan-method T|null one($db = null) + * @psalm-method T|null one($db = null) + * @phpstan-method T[] all($db = null) + * @psalm-method T[] all($db = null) */ class ActiveQuery extends Query implements ActiveQueryInterface { From 2b6f0be71572639be0fc948baa22bd8802651afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= <63721828+max-s-lab@users.noreply.github.com> Date: Mon, 28 Apr 2025 23:27:06 +0400 Subject: [PATCH 05/13] Added and fixed Psalm/PHPStan annotations for ActiveRecord and ActiveQuery (#20363) --- framework/db/ActiveQuery.php | 37 +++++++++++------------------------ framework/db/ActiveRecord.php | 6 ++++++ 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/framework/db/ActiveQuery.php b/framework/db/ActiveQuery.php index ed1e350f66..7bfa3b8206 100644 --- a/framework/db/ActiveQuery.php +++ b/framework/db/ActiveQuery.php @@ -71,10 +71,21 @@ use yii\base\InvalidConfigException; * @since 2.0 * * @template T of (ActiveRecord|array) + * * @phpstan-method T|null one($db = null) * @psalm-method T|null one($db = null) + * * @phpstan-method T[] all($db = null) * @psalm-method T[] all($db = null) + * + * @phpstan-method ($value is true ? (T is array ? self : self) : self) asArray($value = true) + * @psalm-method ($value is true ? (T is array ? self : self) : self) asArray($value = true) + * + * @phpstan-method BatchQueryResult batch($batchSize = 100, $db = null) + * @psalm-method BatchQueryResult batch($batchSize = 100, $db = null) + * + * @phpstan-method BatchQueryResult each($batchSize = 100, $db = null) + * @psalm-method BatchQueryResult each($batchSize = 100, $db = null) */ class ActiveQuery extends Query implements ActiveQueryInterface { @@ -320,32 +331,6 @@ class ActiveQuery extends Query implements ActiveQueryInterface return null; } - /** - * {@inheritdoc} - * - * @return BatchQueryResult - * @psalm-return T[][]|BatchQueryResult - * @phpstan-return T[][]|BatchQueryResult - * @codeCoverageIgnore - */ - public function batch($batchSize = 100, $db = null) - { - return parent::batch($batchSize, $db); - } - - /** - * {@inheritdoc} - * - * @return BatchQueryResult - * @psalm-return T[]|BatchQueryResult - * @phpstan-return T[]|BatchQueryResult - * @codeCoverageIgnore - */ - public function each($batchSize = 100, $db = null) - { - return parent::each($batchSize, $db); - } - /** * Creates a DB command that can be used to execute this query. * @param Connection|null $db the DB connection used to create the DB command. diff --git a/framework/db/ActiveRecord.php b/framework/db/ActiveRecord.php index 130285617e..3714e43a84 100644 --- a/framework/db/ActiveRecord.php +++ b/framework/db/ActiveRecord.php @@ -156,6 +156,9 @@ class ActiveRecord extends BaseActiveRecord * @param string $sql the SQL statement to be executed * @param array $params parameters to be bound to the SQL statement during execution. * @return ActiveQuery the newly created [[ActiveQuery]] instance + * + * @phpstan-return ActiveQuery + * @psalm-return ActiveQuery */ public static function findBySql($sql, $params = []) { @@ -408,6 +411,9 @@ class ActiveRecord extends BaseActiveRecord /** * {@inheritdoc} * @return ActiveQuery the newly created [[ActiveQuery]] instance. + * + * @phpstan-return ActiveQuery + * @psalm-return ActiveQuery */ public static function find() { From fbc86d8bb97e716db07e311f1e7c39bd0564e670 Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 29 Apr 2025 02:32:42 -0700 Subject: [PATCH 06/13] Adds Irish (Gaelic) translations file and language option ('ga') to messages/config (#20364) --- framework/messages/config.php | 7 +- framework/messages/ga/yii.php | 148 ++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 framework/messages/ga/yii.php diff --git a/framework/messages/config.php b/framework/messages/config.php index 35d2b9f55b..e50668b756 100644 --- a/framework/messages/config.php +++ b/framework/messages/config.php @@ -14,9 +14,10 @@ return [ // array, required, list of language codes that the extracted messages // should be translated to. For example, ['zh-CN', 'de']. 'languages' => [ - 'af', 'ar', 'az', 'be', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'el', 'es', 'et', 'fa', 'fi', 'fr', 'he', 'hi', - 'pt-BR', 'ro', 'hr', 'hu', 'hy', 'id', 'it', 'ja', 'ka', 'kk', 'ko', 'kz', 'lt', 'lv', 'ms', 'nb-NO', 'nl', - 'pl', 'pt', 'ru', 'sk', 'sl', 'sr', 'sr-Latn', 'sv', 'tg', 'th', 'tr', 'uk', 'uz', 'uz-Cy', 'vi', 'zh', 'zh-TW' + 'af', 'ar', 'az', 'be', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'el', 'es', 'et', 'fa', 'fi', 'fr', 'ga', 'he', + 'hi', 'pt-BR', 'ro', 'hr', 'hu', 'hy', 'id', 'it', 'ja', 'ka', 'kk', 'ko', 'kz', 'lt', 'lv', 'ms', 'nb-NO', + 'nl', 'pl', 'pt', 'ru', 'sk', 'sl', 'sr', 'sr-Latn', 'sv', 'tg', 'th', 'tr', 'uk', 'uz', 'uz-Cy', 'vi', + 'zh', 'zh-TW' ], // string, the name of the function for translating messages. // Defaults to 'Yii::t'. This is used as a mark to find the messages to be diff --git a/framework/messages/ga/yii.php b/framework/messages/ga/yii.php new file mode 100644 index 0000000000..1b190270bc --- /dev/null +++ b/framework/messages/ga/yii.php @@ -0,0 +1,148 @@ + ' agus ', + '"{attribute}" does not support operator "{operator}".' => '"{attribute}" ní thacaíonn oibreoir "{operator}".', + '(not set)' => '(gan socrú)', + 'Action not found.' => 'Gníomh gan aimsiú.', + 'Aliases available: {aliases}' => 'Ailiasanna ar fáil: {aliases}', + 'An internal server error occurred.' => 'Tharla earráid freastalaí inmheánach.', + 'Are you sure you want to delete this item?' => 'An bhfuil tú cinnte gur mhaith leat an mhír seo a scriosadh?', + 'Condition for "{attribute}" should be either a value or valid operator specification.' => 'Ba cheart go mbeadh an coinníoll le haghaidh "{attribute}" ina luach nó ina shonraíocht oibritheora bailí.', + 'Delete' => 'Scrios', + 'Error' => 'Earráid', + 'File upload failed.' => 'Theip ar uaslódáil an chomhaid.', + 'Home' => 'Baile', + 'Invalid data received for parameter "{param}".' => 'Sonraí neamhbhailí faighte don pharaiméadar "{param}".', + 'Login Required' => 'Logáil Isteach ag Teastáil', + 'Missing required arguments: {params}' => 'Argóintí riachtanacha in easnamh: {params}', + 'Missing required parameters: {params}' => 'Paraiméadair riachtanacha in easnamh: {params}', + 'No' => 'Níl', + 'No results found.' => 'Níor aimsíodh aon torthaí.', + 'Only files with these MIME types are allowed: {mimeTypes}.' => 'Ní cheadaítear ach comhaid leis na cineálacha MIME seo: {mimeTypes}', + 'Only files with these extensions are allowed: {extensions}.' => 'Ní cheadaítear ach comhaid leis na síntí seo: {extensions}', + 'Operator "{operator}" must be used with a search attribute.' => 'Oibreoir "{operator}" Ní mór é a úsáid le tréith cuardaigh.', + 'Operator "{operator}" requires multiple operands.' => 'Oibreoir "{operator}" éilíonn oibríochtaí iolracha.', + 'Options available: {options}' => 'Roghanna ar fáil: {options}', + 'Page not found.' => 'Ní bhfuarthas an leathanach.', + 'Please fix the following errors:' => 'Ceartaigh na hearráidí seo a leanas le do thoil:', + 'Please upload a file.' => 'Le do thoil uaslódáil comhad.', + 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => 'Ag taispeáint {begin, number}-{end, number} de {totalCount, number} {totalCount, plural, one{mír} other{míreanna}}.', + 'The combination {values} of {attributes} has already been taken.' => 'An meascán {values} de {attributes} Tá glactha cheana féin.', + 'The file "{file}" is not an image.' => 'An comhad "{file}" nach íomhá í.', + 'The file "{file}" is too big. Its size cannot exceed {formattedLimit}.' => 'An comhad "{file}" ró-mhór. Ní féidir a mhéid a shárú {formattedLimit}.', + 'The file "{file}" is too small. Its size cannot be smaller than {formattedLimit}.' => 'An comhad "{file}" ró-bheag. Ní féidir a mhéid a bheith níos lú ná {formattedLimit}.', + 'The format of {attribute} is invalid.' => 'Formáid na {attribute} neamhbhailí.', + 'The format of {filter} is invalid.' => 'Formáid na {filter} neamhbhailí.', + 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'An íomhá "{file}" ró-mhór. Ní féidir leis an airde a bheith níos mó ná {limit, number} {limit, plural, one{pixel} other{pixels}}.', + 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'An íomhá "{file}" ró-mhór. Ní féidir leis an leithead a bheith níos mó ná {limit, number} {limit, plural, one{pixel} other{pixels}}.', + 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'An íomhá "{file}" ró-bheag. Ní féidir leis an airde a bheith níos lú ná {limit, number} {limit, plural, one{pixel} other{pixels}}.', + 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'An íomhá "{file}" ró-bheag. Ní féidir leis an leithead a bheith níos lú ná {limit, number} {limit, plural, one{pixel} other{pixels}}.', + 'The requested view "{name}" was not found.' => 'An radharc iarrtha "{name}" níor aimsíodh', + 'The verification code is incorrect.' => 'Tá an cód fíoraithe mícheart', + 'Total {count, number} {count, plural, one{item} other{items}}.' => 'Iomlán {count, number} {count, plural, one{mír} other{míreanna}}.', + 'Unable to verify your data submission.' => 'Ní féidir d\'aighneacht sonraí a fhíorú', + 'Unknown alias: -{name}' => 'Ailias anaithnid: -{name}', + 'Unknown filter attribute "{attribute}"' => 'Aitreabúid scagaire anaithnid "{attribute}"', + 'Unknown option: --{name}' => 'Rogha anaithnid: --{name}', + 'Update' => 'Nuashonrú', + 'View' => 'Amharc', + 'Yes' => 'Tá', + 'You are not allowed to perform this action.' => 'Níl cead agat an gníomh seo a dhéanamh.', + 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Is féidir leat a uaslódáil ar a mhéad {limit, number} {limit, plural, one{file} other{files}}.', + 'You should upload at least {limit, number} {limit, plural, one{file} other{files}}.' => 'Ba chóir duit a uaslódáil ar a laghad {limit, number} {limit, plural, one{file} other{files}}.', + 'in {delta, plural, =1{a day} other{# days}}' => 'isteach {delta, plural, =1{lá} other{# laethanta}}', + 'in {delta, plural, =1{a minute} other{# minutes}}' => 'isteach {delta, plural, =1{nóiméad} other{# nóiméad}}', + 'in {delta, plural, =1{a month} other{# months}}' => 'isteach {delta, plural, =1{mí} other{# mhí}}', + 'in {delta, plural, =1{a second} other{# seconds}}' => 'isteach {delta, plural, =1{dara} other{# soicind}}', + 'in {delta, plural, =1{a year} other{# years}}' => 'isteach {delta, plural, =1{bliain} other{# blianta}}', + 'in {delta, plural, =1{an hour} other{# hours}}' => 'isteach {delta, plural, =1{uair an chloig} other{# uair an chloig}}', + 'just now' => 'díreach anois', + 'the input value' => 'an luach ionchuir', + '{attribute} "{value}" has already been taken.' => '{attribute} "{value}" Tá glactha cheana féin', + '{attribute} cannot be blank.' => '{attribute} Ní féidir a bheith bán.', + '{attribute} contains wrong subnet mask.' => '{attribute} Tá masc subnet mícheart.', + '{attribute} is invalid.' => '{attribute} neamhbhailí.', + '{attribute} is not a valid URL.' => '{attribute} nach URL bailí é.', + '{attribute} is not a valid email address.' => '{attribute} nach seoladh ríomhphoist bailí é.', + '{attribute} is not in the allowed range.' => '{attribute} nach bhfuil sa raon ceadaithe.', + '{attribute} must be "{requiredValue}".' => '{attribute} caithfidh go bhfuil "{requiredValue}".', + '{attribute} must be a number.' => '{attribute} caithfidh gur uimhir é.', + '{attribute} must be a string.' => '{attribute} Ní mór a bheith ina teaghrán.', + '{attribute} must be a valid IP address.' => '{attribute} caithfidh gur seoladh IP bailí é.', + '{attribute} must be an IP address with specified subnet.' => '{attribute} Ní mór seoladh IP a bheith ann le folíon sonraithe.', + '{attribute} must be an integer.' => '{attribute} Ní mór a bheith ina slánuimhir.', + '{attribute} must be either "{true}" or "{false}".' => '{attribute} Ní mór ceachtar "{true}" nó "{false}".', + '{attribute} must be equal to "{compareValueOrAttribute}".' => '{attribute} Ní mór a bheith comhionann le "{compareValueOrAttribute}".', + '{attribute} must be greater than "{compareValueOrAttribute}".' => '{attribute} ní mór a bheith níos mó ná "{compareValueOrAttribute}".', + '{attribute} must be greater than or equal to "{compareValueOrAttribute}".' => '{attribute} a bheith níos mó ná nó cothrom le "{compareValueOrAttribute}".', + '{attribute} must be less than "{compareValueOrAttribute}".' => '{attribute} Ní mór a bheith níos lú ná "{compareValueOrAttribute}".', + '{attribute} must be less than or equal to "{compareValueOrAttribute}".' => '{attribute} ní mór a bheith níos lú ná nó cothrom le "{compareValueOrAttribute}".', + '{attribute} must be no greater than {max}.' => '{attribute} Ní mór a bheith níos mó ná {max}.', + '{attribute} must be no less than {min}.' => '{attribute} Ní mór a bheith níos lú ná{min}.', + '{attribute} must not be a subnet.' => '{attribute} Ní mór a bheith ina subnet.', + '{attribute} must not be an IPv4 address.' => '{attribute} níor cheart gur seoladh IPv4 é.', + '{attribute} must not be an IPv6 address.' => '{attribute} níor cheart gur seoladh IPv6 é.', + '{attribute} must not be equal to "{compareValueOrAttribute}".' => '{attribute} Ní mór a bheith comhionann le "{compareValueOrAttribute}".', + '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} chóir go bhfuil ar a laghad {min, number} {min, plural, one{carachtar} other{carachtair}}.', + '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} chóir go bhfuil ar a mhéad {max, number} {max, plural, one{carachtar} other{carachtair}}.', + '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} chóir go bhfuil {length, number} {length, plural, one{carachtar} other{carachtair}}.', + '{compareAttribute} is invalid.' => '{compareAttribute} neamhbhailí.', + '{delta, plural, =1{1 day} other{# days}}' => '{delta, plural, =1{1 lá} eile{# laethanta}}', + '{delta, plural, =1{1 hour} other{# hours}}' => '{delta, plural, =1{1 uair an chloig} eile{# uair an chloig}}', + '{delta, plural, =1{1 minute} other{# minutes}}' => '{delta, plural, =1{1 nóiméad} eile{# nóiméad}}', + '{delta, plural, =1{1 month} other{# months}}' => '{delta, plural, =1{1 mí} eile{# mhí}}', + '{delta, plural, =1{1 second} other{# seconds}}' => '{delta, plural, =1{1 dara} eile{# soicind}}', + '{delta, plural, =1{1 year} other{# years}}' => '{delta, plural, =1{1 bliain} eile{# blianta}}', + '{delta, plural, =1{a day} other{# days}} ago' => '{delta, plural, =1{1 lá} eile{# laethanta}} ó shin', + '{delta, plural, =1{a minute} other{# minutes}} ago' => '{delta, plural, =1{1 nóiméad} eile{# nóiméad}} ó shin', + '{delta, plural, =1{a month} other{# months}} ago' => '{delta, plural, =1{1 mí} eile{# mhí}} ó shin', + '{delta, plural, =1{a second} other{# seconds}} ago' => '{delta, plural, =1{1 dara} eile{# soicind}} ó shin', + '{delta, plural, =1{a year} other{# years}} ago' => '{delta, plural, =1{1 bliain} eile{# blianta}} ó shin', + '{delta, plural, =1{an hour} other{# hours}} ago' => '{delta, plural, =1{1 uair an chloig} eile{# uair an chloig}} ó shin', + '{nFormatted} B' => '{nFormatted} B', + '{nFormatted} GB' => '{nFormatted} GB', + '{nFormatted} GiB' => '{nFormatted} GiB', + '{nFormatted} KiB' => '{nFormatted} KiB', + '{nFormatted} MB' => '{nFormatted} MB', + '{nFormatted} MiB' => '{nFormatted} MiB', + '{nFormatted} PB' => '{nFormatted} PB', + '{nFormatted} PiB' => '{nFormatted} PiB', + '{nFormatted} TB' => '{nFormatted} TB', + '{nFormatted} TiB' => '{nFormatted} TiB', + '{nFormatted} kB' => '{nFormatted} kB', + '{nFormatted} {n, plural, =1{byte} other{bytes}}' => '{nFormatted} {n, plural, =1{beart} eile{bearta}}', + '{nFormatted} {n, plural, =1{gibibyte} other{gibibytes}}' => '{nFormatted} {n, plural, =1{gibibheart} eile{gibítí}}', + '{nFormatted} {n, plural, =1{gigabyte} other{gigabytes}}' => '{nFormatted} {n, plural, =1{gigabyte} eile{ghigibheart}}', + '{nFormatted} {n, plural, =1{kibibyte} other{kibibytes}}' => '{nFormatted} {n, plural, =1{cibeibít} eile{cibítí}}', + '{nFormatted} {n, plural, =1{kilobyte} other{kilobytes}}' => '{nFormatted} {n, plural, =1{cilibheart} eile{cilibheart}}', + '{nFormatted} {n, plural, =1{mebibyte} other{mebibytes}}' => '{nFormatted} {n, plural, =1{meibít} eile{meibítí}}', + '{nFormatted} {n, plural, =1{megabyte} other{megabytes}}' => '{nFormatted} {n, plural, =1{meigibheart} eile{megabytes}}', + '{nFormatted} {n, plural, =1{pebibyte} other{pebibytes}}' => '{nFormatted} {n, plural, =1{peibít} eile{peibít}}', + '{nFormatted} {n, plural, =1{petabyte} other{petabytes}}' => '{nFormatted} {n, plural, =1{peitibít} eile{peiteabóid}}', + '{nFormatted} {n, plural, =1{tebibyte} other{tebibytes}}' => '{nFormatted} {n, plural, =1{teibít} eile{teibítí}}', + '{nFormatted} {n, plural, =1{terabyte} other{terabytes}}' => '{nFormatted} {n, plural, =1{teiribíte} eile{teiribít}}', +]; From 0b5398707c92ba7569e79034ca63dc4d8890c094 Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 30 Apr 2025 23:57:25 -0700 Subject: [PATCH 07/13] Adds Maltese translations file and language option ('mt') to messages/config (#20369) --- framework/messages/config.php | 4 +- framework/messages/mt/yii.php | 141 ++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 framework/messages/mt/yii.php diff --git a/framework/messages/config.php b/framework/messages/config.php index e50668b756..f7f0aa6b22 100644 --- a/framework/messages/config.php +++ b/framework/messages/config.php @@ -15,8 +15,8 @@ return [ // should be translated to. For example, ['zh-CN', 'de']. 'languages' => [ 'af', 'ar', 'az', 'be', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'el', 'es', 'et', 'fa', 'fi', 'fr', 'ga', 'he', - 'hi', 'pt-BR', 'ro', 'hr', 'hu', 'hy', 'id', 'it', 'ja', 'ka', 'kk', 'ko', 'kz', 'lt', 'lv', 'ms', 'nb-NO', - 'nl', 'pl', 'pt', 'ru', 'sk', 'sl', 'sr', 'sr-Latn', 'sv', 'tg', 'th', 'tr', 'uk', 'uz', 'uz-Cy', 'vi', + 'hi', 'pt-BR', 'ro', 'hr', 'hu', 'hy', 'id', 'it', 'ja', 'ka', 'kk', 'ko', 'kz', 'lt', 'lv', 'ms', 'mt', + 'nb-NO', 'nl', 'pl', 'pt', 'ru', 'sk', 'sl', 'sr', 'sr-Latn', 'sv', 'tg', 'th', 'tr', 'uk', 'uz', 'uz-Cy', 'vi', 'zh', 'zh-TW' ], // string, the name of the function for translating messages. diff --git a/framework/messages/mt/yii.php b/framework/messages/mt/yii.php new file mode 100644 index 0000000000..3eb4b72128 --- /dev/null +++ b/framework/messages/mt/yii.php @@ -0,0 +1,141 @@ + ' u ', + '"{attribute}" does not support operator "{operator}".' => '"{attribute}" ma jappoġġjax l-operatur "{operator}".', + '(not set)' => '(mhux issettjat)', + 'Action not found.' => 'Azzjoni ma nstabitx.', + 'Aliases available: {aliases}' => 'Alias disponibbli: {aliases}', + 'An internal server error occurred.' => 'Sar żball intern tas-server.', + 'Are you sure you want to delete this item?' => 'Int żgur li trid tħassar dan l-oġġett?', + 'Condition for "{attribute}" should be either a value or valid operator specification.' => 'Kundizzjoni għal "{attribute}" għandu jkun jew valur jew speċifikazzjoni valida tal-operatur.', + 'Delete' => 'Ħassar', + 'Error' => 'Żball', + 'File upload failed.' => 'It-tlugħ tal-fajl falla.', + 'Home' => 'Dar', + 'Invalid data received for parameter "{param}".' => 'Data invalida riċevuta għall-parametru "{param}".', + 'Login Required' => 'Login Meħtieġa', + 'Missing required arguments: {params}' => 'Argumenti meħtieġa nieqsa: {params}', + 'Missing required parameters: {params}' => 'Parametri meħtieġa nieqsa: {params}', + 'No' => 'Nru', + 'No results found.' => 'Ma nstab l-ebda riżultat.', + 'Only files with these MIME types are allowed: {mimeTypes}.' => 'Fajls b\'dawn it-tipi MIME biss huma permessi: {mimeTypes}.', + 'Only files with these extensions are allowed: {extensions}.' => 'Fajls b\'dawn l-estensjonijiet biss huma permessi: {extensions}.', + 'Operator "{operator}" must be used with a search attribute.' => 'Operatur "{operator}" għandu jintuża ma\' attribut ta\' tfittxija.', + 'Operator "{operator}" requires multiple operands.' => 'Operatur "{operator}" teħtieġ operandi multipli.', + 'Options available: {options}' => 'Għażliet disponibbli: {options}', + 'Page not found.' => 'Paġna mhux misjuba.', + 'Please fix the following errors:' => 'Jekk jogħġbok waħħal l-iżbalji li ġejjin:', + 'Please upload a file.' => 'Jekk jogħġbok ittella\' fajl.', + 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.' => 'Wiri {begin, number}-{end, number} ta {totalCount, number} {totalCount, plural, one{oġġett} other{oġġetti}}.', + 'The combination {values} of {attributes} has already been taken.' => 'Il-kombinazzjoni {values} ta {attributes} diġà ttieħdet.', + 'The file "{file}" is not an image.' => 'Il-fajl "{file}" mhix immaġni', + 'The file "{file}" is too big. Its size cannot exceed {formattedLimit}.' => 'Il-fajl "{file}" hija kbira wisq. Id-daqs tiegħu ma jistax jaqbeż {formattedLimit}.', + 'The file "{file}" is too small. Its size cannot be smaller than {formattedLimit}.' => 'Il-fajl "{file}" huwa żgħir wisq. Id-daqs tiegħu ma jistax ikun iżgħar minn {formattedLimit}.', + 'The format of {attribute} is invalid.' => 'Il-format ta\' {attribute} hija invalida.', + 'The format of {filter} is invalid.' => 'Il-format ta\' {filter} hija invalida.', + 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'L-immaġni "{file}" hija kbira wisq. L-għoli ma jistax ikun akbar minn {limit, number} {limit, plural, one{pixel} other{pixels}}.', + 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'L-immaġni "{file}" hija kbira wisq. Il-wisa \'ma tistax tkun akbar minn {limit, number} {limit, plural, one{pixel} other{pixels}}.', + 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'L-immaġni "{file}" huwa żgħir wisq. L-għoli ma jistax ikun iżgħar minn {limit, number} {limit, plural, one{pixel} other{pixels}}.', + 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'L-immaġni "{file}" huwa żgħir wisq. Il-wisa \'ma tistax tkun iżgħar minn {limit, number} {limit, plural, one{pixel} other{pixels}}.', + 'The requested view "{name}" was not found.' => 'Il-veduta mitluba "{name}" ma nstabx.', + 'The verification code is incorrect.' => 'Il-kodiċi ta\' verifika mhux korrett.', + 'Total {count, number} {count, plural, one{item} other{items}}.' => 'Total {count, number} {count, plural, one{oġġett} other{oġġetti}}.', + 'Unable to verify your data submission.' => 'Ma tistax tivverifika s-sottomissjoni tad-dejta tiegħek.', + 'Unknown alias: -{name}' => 'Psewdonimu mhux magħruf: -{name}', + 'Unknown filter attribute "{attribute}"' => 'Attribut tal-filtru mhux magħruf "{attribute}"', + 'Unknown option: --{name}' => 'Għażla mhux magħrufa: --{name}', + 'Update' => 'Aġġornament', + 'View' => 'Ara', + 'Yes' => 'Iva', + 'You are not allowed to perform this action.' => 'M\'intix permess li twettaq din l-azzjoni.', + 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Tista \'ttella\' l-aktar {limit, number} {limit, plural, one{file} other{files}}.', + 'You should upload at least {limit, number} {limit, plural, one{file} other{files}}.' => 'Għandek ittella mill-inqas {limit, number} {limit, plural, one{file} other{files}}.', + 'in {delta, plural, =1{a day} other{# days}}' => 'fi {delta, plural, =1{a jum} other{# jiem}}', + 'in {delta, plural, =1{a minute} other{# minutes}}' => 'fi {delta, plural, =1{minuta} other{# minuti}}', + 'in {delta, plural, =1{a month} other{# months}}' => 'fi {delta, plural, =1{xahar} other{# xhur}}', + 'in {delta, plural, =1{a second} other{# seconds}}' => 'fi {delta, plural, =1{it-tieni} other{# sekondi}}', + 'in {delta, plural, =1{a year} other{# years}}' => 'fi {delta, plural, =1{sena} other{# snin}}', + 'in {delta, plural, =1{an hour} other{# hours}}' => 'fi {delta, plural, =1{siegħa} other{# sigħat}}', + 'just now' => 'biss issa', + 'the input value' => 'il-valur tad-dħul', + '{attribute} "{value}" has already been taken.' => '{attribute} "{value}" diġà ttieħdet.', + '{attribute} cannot be blank.' => '{attribute} ma jistax ikun vojt.', + '{attribute} contains wrong subnet mask.' => '{attribute} fih subnet mask ħażina.', + '{attribute} is invalid.' => '{attribute} hija invalida.', + '{attribute} is not a valid URL.' => '{attribute} mhuwiex URL validu.', + '{attribute} is not a valid email address.' => '{attribute} mhuwiex indirizz elettroniku validu.', + '{attribute} is not in the allowed range.' => '{attribute} mhix fil-medda permessa.', + '{attribute} must be "{requiredValue}".' => '{attribute} għandu jkun "{requiredValue}".', + '{attribute} must be a number.' => '{attribute} irid ikun numru.', + '{attribute} must be a string.' => '{attribute} għandu jkun spag.', + '{attribute} must be a valid IP address.' => '{attribute} għandu jkun indirizz IP validu.', + '{attribute} must be an IP address with specified subnet.' => '{attribute} ', + '{attribute} must be an integer.' => '{attribute} għandu jkun numru sħiħ.', + '{attribute} must be either "{true}" or "{false}".' => '{attribute} trid tkun jew "{true}" jew "{false}".', + '{attribute} must be equal to "{compareValueOrAttribute}".' => '{attribute} trid tkun ugwali għal "{compareValueOrAttribute}".', + '{attribute} must be greater than "{compareValueOrAttribute}".' => '{attribute} għandu jkun akbar minn "{compareValueOrAttribute}".', + '{attribute} must be greater than or equal to "{compareValueOrAttribute}".' => '{attribute} għandu jkun akbar minn jew ugwali għal "{compareValueOrAttribute}".', + '{attribute} must be less than "{compareValueOrAttribute}".' => '{attribute} għandu jkun inqas minn "{compareValueOrAttribute}".', + '{attribute} must be less than or equal to "{compareValueOrAttribute}".' => '{attribute} għandu jkun inqas minn jew ugwali għal "{compareValueOrAttribute}".', + '{attribute} must be no greater than {max}.' => '{attribute} m\'għandux ikun akbar minn {max}.', + '{attribute} must be no less than {min}.' => '{attribute} għandu jkun mhux inqas minn {min}.', + '{attribute} must not be a subnet.' => '{attribute} m\'għandux ikun subnet.', + '{attribute} must not be an IPv4 address.' => '{attribute} m\'għandux ikun indirizz IPv4.', + '{attribute} must not be an IPv6 address.' => '{attribute} m\'għandux ikun indirizz IPv6.', + '{attribute} must not be equal to "{compareValueOrAttribute}".' => '{attribute} m\'għandux ikun ugwali għal "{compareValueOrAttribute}".', + '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} għandu jkun fih mill-inqas {min, number} {min, plural, one{character} other{characters}}.', + '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} għandu jkun fih l-aktar {max, number} {max, plural, one{character} other{characters}}.', + '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} għandu jkun fih {length, number} {length, plural, one{character} other{characters}}.', + '{compareAttribute} is invalid.' => '{compareAttribute} hija invalida', + '{delta, plural, =1{1 day} other{# days}}' => '{delta, plural, =1{1 jum} other{# jiem}}', + '{delta, plural, =1{1 hour} other{# hours}}' => '{delta, plural, =1{1 siegħa} other{# sigħat}}', + '{delta, plural, =1{1 minute} other{# minutes}}' => '{delta, plural, =1{1 minuta} other{# minuti}}', + '{delta, plural, =1{1 month} other{# months}}' => '{delta, plural, =1{1 xahar} other{# xhur}}', + '{delta, plural, =1{1 second} other{# seconds}}' => '{delta, plural, =1{1 it-tieni} other{# sekondi}}', + '{delta, plural, =1{1 year} other{# years}}' => '{delta, plural, =1{1 sena} other{# snin}}', + '{delta, plural, =1{a day} other{# days}} ago' => '{delta, plural, =1{jum} other{# jiem}} ago', + '{delta, plural, =1{a minute} other{# minutes}} ago' => '{delta, plural, =1{minuta} other{# minuti}} ago', + '{delta, plural, =1{a month} other{# months}} ago' => '{delta, plural, =1{xahar} other{# xhur}} ago', + '{delta, plural, =1{a second} other{# seconds}} ago' => '{delta, plural, =1{it-tieni} other{# sekondi}} ago', + '{delta, plural, =1{a year} other{# years}} ago' => '{delta, plural, =1{sena} other{# snin}} ago', + '{delta, plural, =1{an hour} other{# hours}} ago' => '{delta, plural, =1{siegħa} other{# sigħat}} ago', + '{nFormatted} B' => '{nFormatted} B', + '{nFormatted} GB' => '{nFormatted} GB', + '{nFormatted} GiB' => '{nFormatted} GiB', + '{nFormatted} KiB' => '{nFormatted} KiB', + '{nFormatted} MB' => '{nFormatted} MB', + '{nFormatted} MiB' => '{nFormatted} MiB', + '{nFormatted} PB' => '{nFormatted} PB', + '{nFormatted} PiB' => '{nFormatted} PiB', + '{nFormatted} TB' => '{nFormatted} TB', + '{nFormatted} TiB' => '{nFormatted} TiB', + '{nFormatted} kB' => '{nFormatted} kB', + '{nFormatted} {n, plural, =1{byte} other{bytes}}' => '{nFormatted} {n, plural, =1{byte} other{bytes}}', + '{nFormatted} {n, plural, =1{gibibyte} other{gibibytes}}' => '{nFormatted} {n, plural, =1{gibibyte} other{gibibytes}}', + '{nFormatted} {n, plural, =1{gigabyte} other{gigabytes}}' => '{nFormatted} {n, plural, =1{gigabyte} other{gigabytes}}', + '{nFormatted} {n, plural, =1{kibibyte} other{kibibytes}}' => '{nFormatted} {n, plural, =1{kibibyte} other{kibibytes}}', + '{nFormatted} {n, plural, =1{kilobyte} other{kilobytes}}' => '{nFormatted} {n, plural, =1{kilobyte} other{kilobytes}}', + '{nFormatted} {n, plural, =1{mebibyte} other{mebibytes}}' => '{nFormatted} {n, plural, =1{mebibyte} other{mebibytes}}', + '{nFormatted} {n, plural, =1{megabyte} other{megabytes}}' => '{nFormatted} {n, plural, =1{megabyte} other{megabytes}}', + '{nFormatted} {n, plural, =1{pebibyte} other{pebibytes}}' => '{nFormatted} {n, plural, =1{pebibyte} other{pebibytes}}', + '{nFormatted} {n, plural, =1{petabyte} other{petabytes}}' => '{nFormatted} {n, plural, =1{petabyte} other{petabytes}}', + '{nFormatted} {n, plural, =1{tebibyte} other{tebibytes}}' => '{nFormatted} {n, plural, =1{tebibyte} other{tebibytes}}', + '{nFormatted} {n, plural, =1{terabyte} other{terabytes}}' => '{nFormatted} {n, plural, =1{terabyte} other{terabytes}}', +]; From ab6fd4c9c4bb46e73639fd60de5725891b244388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= <63721828+max-s-lab@users.noreply.github.com> Date: Sun, 4 May 2025 13:41:36 +0400 Subject: [PATCH 08/13] Added PHPStan/Psalm annotations for AssetBundle, AssetManager and View (#20372) --- framework/CHANGELOG.md | 4 ++++ framework/web/AssetBundle.php | 27 +++++++++++++++++++++++++++ framework/web/AssetManager.php | 21 +++++++++++++++++++++ framework/web/View.php | 28 ++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 37e07e23c6..04627b6b3a 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -9,6 +9,10 @@ Yii Framework 2 Change Log - Bug #8298: Loading fixtures does not update table sequence for Postgresql database (mtangoo) - Bug #20347: Fix compatibility with PHP 8.4: remove usage of `session.use_trans_sid` and `session.use_only_cookies` (tehmaestro) - Bug #20355: Fix SQL syntax for resetting sequence in `QueryBuilder` for `MSSQL` (terabytesoftw) +- Enh #20354: Add PHPStan/Psalm annotations for `Container` and `Instance` (max-s-lab) +- Enh #20361: Add PHPStan/Psalm annotations for `ActiveQuery` (max-s-lab) +- Enh #20363: Add PHPStan/Psalm annotations for `ActiveRecord` and `ActiveQuery` (max-s-lab) +- Enh #20372: Add PHPStan/Psalm annotations for `AssetBundle`, `AssetManager` and `View` (max-s-lab) 2.0.52 February 13, 2025 diff --git a/framework/web/AssetBundle.php b/framework/web/AssetBundle.php index 65dab7942b..785262d54f 100644 --- a/framework/web/AssetBundle.php +++ b/framework/web/AssetBundle.php @@ -26,6 +26,15 @@ use yii\helpers\Url; * * @author Qiang Xue * @since 2.0 + * + * @phpstan-import-type RegisterJsFileOptions from View + * @psalm-import-type RegisterJsFileOptions from View + * + * @phpstan-import-type RegisterCssFileOptions from View + * @psalm-import-type RegisterCssFileOptions from View + * + * @phpstan-import-type PublishOptions from AssetManager + * @psalm-import-type PublishOptions from AssetManager */ class AssetBundle extends BaseObject { @@ -72,6 +81,9 @@ class AssetBundle extends BaseObject * 'yii\bootstrap\BootstrapAsset', * ]; * ``` + * + * @phpstan-var class-string[] + * @psalm-var class-string[] */ public $depends = []; /** @@ -89,6 +101,9 @@ class AssetBundle extends BaseObject * This functionality is available since version 2.0.7. * * Note that only a forward slash "/" should be used as directory separator. + * + * @phpstan-var (string|array)[] + * @psalm-var (string|array)[] */ public $js = []; /** @@ -96,21 +111,33 @@ class AssetBundle extends BaseObject * in one of the three formats as explained in [[js]]. * * Note that only a forward slash "/" should be used as directory separator. + * + * @phpstan-var (string|array)[] + * @psalm-var (string|array)[] */ public $css = []; /** * @var array the options that will be passed to [[View::registerJsFile()]] * when registering the JS files in this bundle. + * + * @phpstan-var RegisterJsFileOptions + * @psalm-var RegisterJsFileOptions */ public $jsOptions = []; /** * @var array the options that will be passed to [[View::registerCssFile()]] * when registering the CSS files in this bundle. + * + * @phpstan-var RegisterCssFileOptions + * @psalm-var RegisterCssFileOptions */ public $cssOptions = []; /** * @var array the options to be passed to [[AssetManager::publish()]] when the asset bundle * is being published. This property is used only when [[sourcePath]] is set. + * + * @phpstan-var PublishOptions + * @psalm-var PublishOptions */ public $publishOptions = []; diff --git a/framework/web/AssetManager.php b/framework/web/AssetManager.php index 0ad3a21cc0..2eceddb4d2 100644 --- a/framework/web/AssetManager.php +++ b/framework/web/AssetManager.php @@ -38,6 +38,24 @@ use yii\helpers\Url; * * @author Qiang Xue * @since 2.0 + * + * @phpstan-type PublishOptions array{ + * only?: string[], + * except?: string[], + * caseSensitive?: bool, + * beforeCopy?: callable, + * afterCopy?: callable, + * forceCopy?: bool, + * } + * + * @psalm-type PublishOptions = array{ + * only?: string[], + * except?: string[], + * caseSensitive?: bool, + * beforeCopy?: callable, + * afterCopy?: callable, + * forceCopy?: bool, + * } */ class AssetManager extends Component { @@ -463,6 +481,9 @@ class AssetManager extends Component * @return array the path (directory or file path) and the URL that the asset is published as. * @throws InvalidArgumentException if the asset to be published does not exist. * @throws InvalidConfigException if the target directory [[basePath]] is not writeable. + * + * @phpstan-param PublishOptions $options + * @psalm-param PublishOptions $options */ public function publish($path, $options = []) { diff --git a/framework/web/View.php b/framework/web/View.php index f4afa9243c..bd730475d5 100644 --- a/framework/web/View.php +++ b/framework/web/View.php @@ -41,6 +41,28 @@ use yii\helpers\Url; * * @author Qiang Xue * @since 2.0 + * + * @phpstan-type RegisterJsFileOptions array{ + * depends?: class-string[], + * position?: int, + * appendTimestamp?: boolean + * } + * + * @psalm-type RegisterJsFileOptions = array{ + * depends?: class-string[], + * position?: int, + * appendTimestamp?: boolean + * } + * + * @phpstan-type RegisterCssFileOptions array{ + * depends?: class-string[], + * appendTimestamp?: boolean + * } + * + * @psalm-type RegisterCssFileOptions = array{ + * depends?: class-string[], + * appendTimestamp?: boolean + * } */ class View extends \yii\base\View { @@ -445,6 +467,9 @@ class View extends \yii\base\View * $url as the key. If two CSS files are registered with the same key, the latter * will overwrite the former. * @throws InvalidConfigException + * + * @phpstan-param RegisterCssFileOptions $options + * @psalm-param RegisterCssFileOptions $options */ public function registerCssFile($url, $options = [], $key = null) { @@ -569,6 +594,9 @@ class View extends \yii\base\View * will overwrite the former. Note that position option takes precedence, thus files registered with the same key, * but different position option will not override each other. * @throws InvalidConfigException + * + * @phpstan-param RegisterJsFileOptions $options + * @psalm-param RegisterJsFileOptions $options */ public function registerJsFile($url, $options = [], $key = null) { From 87d960b85be3d5e2c3c049c0355960bca284642b Mon Sep 17 00:00:00 2001 From: Oleg Poludnenko Date: Sun, 4 May 2025 12:42:46 +0300 Subject: [PATCH 09/13] Fix #20371: Fix "Typed property must not be accessed before initialization" when calling `toArray()` on a model with typed properties without default value --- framework/CHANGELOG.md | 1 + framework/base/ArrayableTrait.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 04627b6b3a..fc183bdfd5 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -9,6 +9,7 @@ Yii Framework 2 Change Log - Bug #8298: Loading fixtures does not update table sequence for Postgresql database (mtangoo) - Bug #20347: Fix compatibility with PHP 8.4: remove usage of `session.use_trans_sid` and `session.use_only_cookies` (tehmaestro) - Bug #20355: Fix SQL syntax for resetting sequence in `QueryBuilder` for `MSSQL` (terabytesoftw) +- Bug #20371: Fix "Typed property must not be accessed before initialization" when calling `toArray()` on a model with typed properties without default value (uaoleg) - Enh #20354: Add PHPStan/Psalm annotations for `Container` and `Instance` (max-s-lab) - Enh #20361: Add PHPStan/Psalm annotations for `ActiveQuery` (max-s-lab) - Enh #20363: Add PHPStan/Psalm annotations for `ActiveRecord` and `ActiveQuery` (max-s-lab) diff --git a/framework/base/ArrayableTrait.php b/framework/base/ArrayableTrait.php index 310c007486..3f18171aa9 100644 --- a/framework/base/ArrayableTrait.php +++ b/framework/base/ArrayableTrait.php @@ -123,7 +123,7 @@ trait ArrayableTrait { $data = []; foreach ($this->resolveFields($fields, $expand) as $field => $definition) { - $attribute = is_string($definition) ? $this->$definition : $definition($this, $field); + $attribute = is_string($definition) ? ($this->$definition ?? null) : $definition($this, $field); if ($recursive) { $nestedFields = $this->extractFieldsFor($fields, $field); From f66ee97a452c45a936689c92d6297c59ab7317e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= <63721828+max-s-lab@users.noreply.github.com> Date: Mon, 5 May 2025 09:24:57 +0400 Subject: [PATCH 10/13] Fix #20374: Add PHPStan/Psalm annotations for `BaseYii`, `BaseObject`, `Component`, `Model`, `Module` and `yii\base\Controller` --- framework/BaseYii.php | 6 ++++++ framework/CHANGELOG.md | 1 + framework/base/BaseObject.php | 3 +++ framework/base/Component.php | 3 +++ framework/base/Controller.php | 6 ++++++ framework/base/Model.php | 33 +++++++++++++++++++++++++++++++++ framework/base/Module.php | 3 +++ 7 files changed, 55 insertions(+) diff --git a/framework/BaseYii.php b/framework/BaseYii.php index 0d39105083..d00943fca5 100644 --- a/framework/BaseYii.php +++ b/framework/BaseYii.php @@ -338,6 +338,12 @@ class BaseYii * @return object the created object * @throws InvalidConfigException if the configuration is invalid. * @see \yii\di\Container + * + * @template T + * @phpstan-param class-string|array{class: class-string, ...}|callable(): T $type + * @psalm-param class-string|array{class: class-string, ...}|callable(): T $type + * @phpstan-return T + * @psalm-return T */ public static function createObject($type, array $params = []) { diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index fc183bdfd5..49f3105b33 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -14,6 +14,7 @@ Yii Framework 2 Change Log - Enh #20361: Add PHPStan/Psalm annotations for `ActiveQuery` (max-s-lab) - Enh #20363: Add PHPStan/Psalm annotations for `ActiveRecord` and `ActiveQuery` (max-s-lab) - Enh #20372: Add PHPStan/Psalm annotations for `AssetBundle`, `AssetManager` and `View` (max-s-lab) +- Enh #20374: Add PHPStan/Psalm annotations for `BaseYii`, `BaseObject`, `Component`, `Model`, `Module` and `yii\base\Controller` (max-s-lab) 2.0.52 February 13, 2025 diff --git a/framework/base/BaseObject.php b/framework/base/BaseObject.php index 174fcd1e99..8ef2f1566c 100644 --- a/framework/base/BaseObject.php +++ b/framework/base/BaseObject.php @@ -100,6 +100,9 @@ class BaseObject implements Configurable * - call the parent implementation at the end of the constructor. * * @param array $config name-value pairs that will be used to initialize the object properties + * + * @phpstan-param array $config + * @psalm-param array $config */ public function __construct($config = []) { diff --git a/framework/base/Component.php b/framework/base/Component.php index 937de6b44e..8fd7c6fa68 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -461,6 +461,9 @@ class Component extends BaseObject * Behaviors declared in this method will be attached to the component automatically (on demand). * * @return array the behavior configurations. + * + * @phpstan-return array + * @psalm-return array */ public function behaviors() { diff --git a/framework/base/Controller.php b/framework/base/Controller.php index b810e5982d..f99d97fcf2 100644 --- a/framework/base/Controller.php +++ b/framework/base/Controller.php @@ -87,6 +87,9 @@ class Controller extends Component implements ViewContextInterface * @param string $id the ID of this controller. * @param Module $module the module that this controller belongs to. * @param array $config name-value pairs that will be used to initialize the object properties. + * + * @phpstan-param array $config + * @psalm-param array $config */ public function __construct($id, $module, $config = []) { @@ -127,6 +130,9 @@ class Controller extends Component implements ViewContextInterface * [[\Yii::createObject()]] will be used later to create the requested action * using the configuration provided here. * @return array + * + * @phpstan-return array * @since 2.0 + * + * @phpstan-property array $attributes + * @psalm-property array $attributes + * + * @phpstan-property-read array $errors + * @psalm-property-read array $errors + * + * @phpstan-property-read array $firstErrors + * @psalm-property-read array $firstErrors */ class Model extends Component implements StaticInstanceInterface, IteratorAggregate, ArrayAccess, Arrayable { @@ -151,6 +160,9 @@ class Model extends Component implements StaticInstanceInterface, IteratorAggreg * * @return array validation rules * @see scenarios() + * + * @phpstan-return array[] + * @psalm-return array[] */ public function rules() { @@ -181,6 +193,9 @@ class Model extends Component implements StaticInstanceInterface, IteratorAggreg * are being validated by the validation rules that apply to the scenario. * * @return array a list of scenarios and the corresponding active attributes. + * + * @phpstan-return array + * @psalm-return array */ public function scenarios() { @@ -293,6 +308,9 @@ class Model extends Component implements StaticInstanceInterface, IteratorAggreg * * @return array attribute labels (name => label) * @see generateAttributeLabel() + * + * @phpstan-return array + * @psalm-return array */ public function attributeLabels() { @@ -313,6 +331,9 @@ class Model extends Component implements StaticInstanceInterface, IteratorAggreg * * @return array attribute hints (name => hint) * @since 2.0.4 + * + * @phpstan-return array + * @psalm-return array */ public function attributeHints() { @@ -580,6 +601,9 @@ class Model extends Component implements StaticInstanceInterface, IteratorAggreg * * @see getFirstErrors() * @see getFirstError() + * + * @phpstan-return array + * @psalm-return array */ public function getErrors($attribute = null) { @@ -596,6 +620,9 @@ class Model extends Component implements StaticInstanceInterface, IteratorAggreg * values are the corresponding error messages. An empty array will be returned if there is no error. * @see getErrors() * @see getFirstError() + * + * @phpstan-return array + * @psalm-return array */ public function getFirstErrors() { @@ -633,6 +660,9 @@ class Model extends Component implements StaticInstanceInterface, IteratorAggreg * @see getErrors() * @see getFirstErrors() * @since 2.0.14 + * + * @phpstan-return string[] + * @psalm-return string[] */ public function getErrorSummary($showAllErrors) { @@ -708,6 +738,9 @@ class Model extends Component implements StaticInstanceInterface, IteratorAggreg * If it is an array, only the attributes in the array will be returned. * @param array $except list of attributes whose value should NOT be returned. * @return array attribute values (name => value). + * + * @phpstan-return array + * @psalm-return array */ public function getAttributes($names = null, $except = []) { diff --git a/framework/base/Module.php b/framework/base/Module.php index 391219939f..a95cfcf4e7 100644 --- a/framework/base/Module.php +++ b/framework/base/Module.php @@ -153,6 +153,9 @@ class Module extends ServiceLocator * @param string $id the ID of this module. * @param Module|null $parent the parent module (if any). * @param array $config name-value pairs that will be used to initialize the object properties. + * + * @phpstan-param array $config + * @psalm-param array $config */ public function __construct($id, $parent = null, $config = []) { From a2259d0c1d4d3f4e14ea322d913bd1a1f6d25471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= <63721828+max-s-lab@users.noreply.github.com> Date: Mon, 5 May 2025 09:27:07 +0400 Subject: [PATCH 11/13] Fix #20373: Fixed the type of the first parameter `yii\base\Controller::bindInjectedParams()` --- framework/CHANGELOG.md | 1 + framework/base/Controller.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 49f3105b33..95339288f9 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -14,6 +14,7 @@ Yii Framework 2 Change Log - Enh #20361: Add PHPStan/Psalm annotations for `ActiveQuery` (max-s-lab) - Enh #20363: Add PHPStan/Psalm annotations for `ActiveRecord` and `ActiveQuery` (max-s-lab) - Enh #20372: Add PHPStan/Psalm annotations for `AssetBundle`, `AssetManager` and `View` (max-s-lab) +- Bug #20373: Fixed the type of the first parameter `yii\base\Controller::bindInjectedParams()` (max-s-lab) - Enh #20374: Add PHPStan/Psalm annotations for `BaseYii`, `BaseObject`, `Component`, `Model`, `Module` and `yii\base\Controller` (max-s-lab) diff --git a/framework/base/Controller.php b/framework/base/Controller.php index f99d97fcf2..494e1c535c 100644 --- a/framework/base/Controller.php +++ b/framework/base/Controller.php @@ -554,7 +554,7 @@ class Controller extends Component implements ViewContextInterface /** * Fills parameters based on types and names in action method signature. - * @param \ReflectionType $type The reflected type of the action parameter. + * @param \ReflectionNamedType $type The reflected type of the action parameter. * @param string $name The name of the parameter. * @param array &$args The array of arguments for the action, this function may append items to it. * @param array &$requestedParams The array with requested params, this function may write specific keys to it. @@ -564,7 +564,7 @@ class Controller extends Component implements ViewContextInterface * (for example an interface type hint) without a proper definition in the container. * @since 2.0.36 */ - final protected function bindInjectedParams(\ReflectionType $type, $name, &$args, &$requestedParams) + final protected function bindInjectedParams(\ReflectionNamedType $type, $name, &$args, &$requestedParams) { // Since it is not a builtin type it must be DI injection. $typeName = $type->getName(); From 3eae59908991086069cebfb17b66a1fa89fddd78 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Mon, 5 May 2025 15:56:36 +0300 Subject: [PATCH 12/13] Update LICENSE to match what's used for Yii3 --- LICENSE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index ee872b9abf..bc5674fe47 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) +Copyright © 2008 by Yii Software (https://www.yiiframework.com/) All rights reserved. Redistribution and use in source and binary forms, with or without @@ -11,7 +11,7 @@ are met: notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Yii Software LLC nor the names of its + * Neither the name of Yii Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. From 47fb7fc78d92ea0738fe4c655ce68430726dbe2f Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Tue, 6 May 2025 21:12:51 +0400 Subject: [PATCH 13/13] Merge pull request #20378 from xepozz/cache-type --- framework/caching/CacheInterface.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/framework/caching/CacheInterface.php b/framework/caching/CacheInterface.php index 0ff387eff1..b9e8035a34 100644 --- a/framework/caching/CacheInterface.php +++ b/framework/caching/CacheInterface.php @@ -188,6 +188,12 @@ interface CacheInterface extends \ArrayAccess * the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. * This parameter is ignored if [[serializer]] is `false`. * @return mixed result of $callable execution + * + * @template TResult of mixed + * @psalm-param callable():TResult|\Closure():TResult $callable + * @phpstan-param callable():TResult|\Closure():TResult $callable + * @psalm-return TResult + * @phpstan-return TResult */ public function getOrSet($key, $callable, $duration = null, $dependency = null); }